package model;
import com.google.common.collect.Lists;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
import java.util.stream.Collector;
import java.util.stream.Collectors;
/**
* 汇总操作,分区,分组,和自定义流收集器
*
* @since 2020年2月23日22:19:26
* {@link java.util.stream.Collectors}
*/
public class Java8StreamTest2 {
public static void main(String[] args) {
// test001();
// test002();
// test003();
// test004();
// test005();
// test006();
// test007();
// test009();
test010();
}
/**
* @see java.util.stream.Collectors#groupingBy(Function)
* @see Collectors#counting() //流的元素个数
* @see Collectors#maxBy(Comparator) //流中最大的
* @see Collectors#minBy(Comparator) //流中最小的
* @see Collectors#averagingInt(ToIntFunction) //流中元素的平均值
* @see Collectors#summingInt(ToIntFunction) //流中的元素求和汇总
* @see Collectors#reducing(BinaryOperator) //流中的元素汇总,可以求和,可以找最大,最小,平均值
* @see Collectors#joining() //字符串连接汇总
*/
public static void test001() {
List<String> list = Lists.newArrayList("xx", "zz", "yy");
String retStr = list.stream().collect(Collectors.joining("|"));
System.out.println(retStr);//xx|zz|yy
List<Integer> list2 = Lists.newArrayList(1, 2, 3, 4, 5, 5, 6);
Optional<Integer> max = list2.stream().collect(Collectors.maxBy(Integer::compareTo));
System.out.println(max.get());//6
Integer max2 = list2.stream().collect(Collectors.reducing(0, Integer::max));
System.out.println(max2);//6
//有拆箱,有性能损耗
Integer sum = list2.stream().collect(Collectors.summingInt(Integer::intValue));
System.out.println(sum);//26
}
/**
* 分组
*/
public static void test002() {
List<Dish> dishes = new ArrayList<>();
dishes.add(Dish.builder().name("apple").type(1).build());
dishes.add(Dish.builder().name("banana").type(1).build());
dishes.add(Dish.builder().name("orange").type(1).build());
dishes.add(Dish.builder().name("fish").type(2).build());
dishes.add(Dish.builder().name("vegetable").type(3).build());
//按类型分组,每组有多少个
Map<Integer, Long> collect = dishes.stream().collect(Collectors.groupingBy(Dish::getType, Collectors.counting()));
System.out.println(collect);//{1=3, 2=1, 3=1}
}
/**
* 多级分组,先按类型分组,在每组按热量分组
*/
public static void test003() {
List<Dish> dishes = new ArrayList<>();
dishes.add(Dish.builder().name("apple").type(1).calories(60).build());
dishes.add(Dish.builder().name("banana").type(1).calories(100).build());
dishes.add(Dish.builder().name("pear").type(1).calories(90).build());
dishes.add(Dish.builder().name("orange").type(1).calories(80).build());
dishes.add(Dish.builder().name("fish").type(2).calories(200).build());
dishes.add(Dish.builder().name("vegetable").type(3).calories(30).build());
//每个类型有哪些,每个类型中高热量的有哪些
Map<Integer, Map<String, List<Dish>>> collect = dishes.stream()
.collect(Collectors.groupingBy(Dish::getType, Collectors.groupingBy(dish -> {
if (dish.getCalories() > 80) return "level calories";
else return "high calories";
})));
System.out.println(collect);
//java8遍历map entrySet 方式推荐
collect.entrySet().stream().forEach(t -> {
System.out.println("===" + t.getKey());
// System.out.println(t.getValue());
t.getValue().entrySet().stream().forEach(map2 -> {
System.out.println(map2.getKey());
System.out.println(map2.getValue());
});
});
/**
* ===1
* level calories
* [Dish(id=0, name=banana, calories=100, isVegetarian=false, type=1), Dish(id=0, name=pear, calories=90, isVegetarian=false, type=1)]
* high calories
* [Dish(id=0, name=apple, calories=60, isVegetarian=false, type=1), Dish(id=0, name=orange, calories=80, isVegetarian=false, type=1)]
* ===2
* level calories
* [Dish(id=0, name=fish, calories=200, isVegetarian=false, type=2)]
* ===3
* high calories
* [Dish(id=0, name=vegetable, calories=30, isVegetarian=false, type=3)]
*/
}
/**
* 多级分组,先按类型分组,在每组取热量最大的
*/
public static void test004() {
List<Dish> dishes = new ArrayList<>();
dishes.add(Dish.builder().name("apple").type(1).calories(60).build());
dishes.add(Dish.builder().name("banana").type(1).calories(100).build());
dishes.add(Dish.builder().name("orange").type(1).calories(80).build());
dishes.add(Dish.builder().name("fish").type(2).calories(200).build());
dishes.add(Dish.builder().name("vegetable").type(3).calories(30).build());
//每个类型有哪些,每个类型中热量最大的
Map<Integer, Optional<Dish>> collect = dishes.stream().collect(Collectors.groupingBy(Dish::getType,
Collectors.maxBy(Comparator.comparing(Dish::getCalories))));
collect.entrySet().stream().forEach(dish -> {
System.out.println(dish.getKey());
System.out.println(dish.getValue().get().getName());
});
/**
* 1
* banana
* 2
* fish
* 3
* vegetable
*/
}
/**
* 把收集器的结果转化为另一种类型
* 查找每个子组中热量最高的Dish
* <p>
* Map<Integer, Optional<Dish>>
* 里面的Optional 包装去掉写法
*/
public static void test005() {
List<Dish> dishes = new ArrayList<>();
dishes.add(Dish.builder().name("apple").type(1).calories(60).build());
dishes.add(Dish.builder().name("banana").type(1).calories(100).build());
dishes.add(Dish.builder().name("orange").type(1).calories(80).build());
dishes.add(Dish.builder().name("fish").type(2).calories(200).build());
dishes.add(Dish.builder().name("vegetable").type(3).calories(30).build());
Map<Integer, Dish> collect = dishes.stream().collect(
Collectors.groupingBy(Dish::getType, //分类函数
Collectors.collectingAndThen(//包装后的收集器
Collectors.maxBy(Comparator.comparingInt(Dish::getCalories)),//取热量最大的
Optional::get)
));
collect.entrySet().forEach(dish -> {
System.out.println(dish.getKey());
System.out.println(dish.getValue());
});
/**
* 1
* Dish(id=0, name=banana, calories=100, isVegetarian=false, type=1)
* 2
* Dish(id=0, name=fish, calories=200, isVegetarian=false, type=2)
* 3
* Dish(id=0, name=vegetable, calories=30, isVegetarian=false, type=3)
*/
}
/**
* 查询每种类型的食谱的能量总和
*
* @see Collectors#groupingBy(Function, Collector)
* @see Collectors#summingInt(ToIntFunction)
*/
public static void test006() {
List<Dish> dishes = getData();
Map<Integer, Integer> collect = dishes.stream().collect(Collectors.groupingBy(Dish::getType, Collectors.summingInt(Dish::getCalories)));
collect.entrySet().forEach(m -> {
System.out.println(m.getKey());
System.out.println(m.getValue());
});
/**
* 1
* 240
* 2
* 200
* 3
* 30
*/
}
private static List<Dish> getData() {
List<Dish> dishes = new ArrayList<>();
dishes.add(Dish.builder().name("apple").type(1).calories(60).isVegetarian(false).build());
dishes.add(Dish.builder().name("banana").type(1).calories(100).isVegetarian(false).build());
dishes.add(Dish.builder().name("orange").type(1).calories(80).isVegetarian(false).build());
dishes.add(Dish.builder().name("fish").type(2).calories(200).isVegetarian(false).build());
dishes.add(Dish.builder().name("Flat Beans").type(3).calories(30).isVegetarian(true).build());//扁豆
return dishes;
}
/**
* groupingby 联合mapping 收集器做转换
*
* @see Collectors#mapping(Function, Collector)
*/
public static void test007() {
List<Dish> dishes = getData();
Map<Integer, Set<String>> collect = dishes.stream().collect(Collectors.groupingBy(Dish::getType, Collectors.mapping(dish -> {
if (dish.getCalories() > 80) return "high dish";
else if (dish.getCalories() > 50) return "normal dish";
else return "level dish";
}, Collectors.toCollection(HashSet::new))));//Collectors.toCollection(HashSet::new)
collect.entrySet().stream().forEach(map -> {
System.out.println(map.getKey());
map.getValue().stream().forEach(System.out::println);
});
/**
* 1
* normal dish
* high dish
* 2
* high dish
* 3
* level dish
*/
}
/**
* 分区
* <p>分区是分组的一种特殊情况,只有true,false 两组</p>
*
* @see Collectors#partitioningBy(Predicate)
*/
public static void test009(){
List<Dish> dishes = getData();
Map<Boolean, List<Dish>> collect = dishes.stream().collect(Collectors.partitioningBy(Dish::isVegetarian));
collect.entrySet().stream().forEach(dish->{
System.out.println(dish.getKey());
dish.getValue().stream().forEach(System.out::println);
});
/**
* false
* Dish(id=0, name=apple, calories=60, isVegetarian=false, type=1)
* Dish(id=0, name=banana, calories=100, isVegetarian=false, type=1)
* Dish(id=0, name=orange, calories=80, isVegetarian=false, type=1)
* Dish(id=0, name=fish, calories=200, isVegetarian=false, type=2)
* true
* Dish(id=0, name=Flat Beans, calories=30, isVegetarian=true, type=3)
*/
}
/**
* 分区的一个重载方法
* @see Collectors#partitioningBy(Predicate, Collector)
*
* //先分区后分组
* 先按是不是蔬菜分组,之后再每组中有哪些类型分组
*/
public static void test010(){
List<Dish> dishes = getData();
Map<Boolean, Map<Integer, List<Dish>>> collect = dishes.stream().collect(Collectors.partitioningBy(Dish::isVegetarian, Collectors.groupingBy(Dish::getType)));
collect.entrySet().stream().forEach(b->{
System.out.println(b);
b.getValue().entrySet().stream().forEach(m->{
System.out.println(m.getKey());
m.getValue().stream().forEach(v-> System.out.println(v.getName()));
});
});
/**
* false={1=[Dish(id=0, name=apple, calories=60, isVegetarian=false, type=1), Dish(id=0, name=banana, calories=100, isVegetarian=false, type=1), Dish(id=0, name=orange, calories=80, isVegetarian=false, type=1)],
* 2=[Dish(id=0, name=fish, calories=200, isVegetarian=false, type=2)]}
* 1
* apple
* banana
* orange
* 2
* fish
* true={3=[Dish(id=0, name=Flat Beans, calories=30, isVegetarian=true, type=3)]}
* 3
* Flat Beans
*/
}
}