文章目录
初识Collector体会Collector的强大
三个主要功能
java.util.stream.Collector
它的实现类
java.util.stream.Collectors
聚合
Apple
public class Apple {
private String color;
private long weight;
public Apple() {
}
public Apple(String color, long weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public long getWeight() {
return weight;
}
public void setWeight(long weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Apple{" +
"color='" + color + '\'' +
", weight=" + weight +
'}';
}
}
聚合
public static void main(String[] args) {
List<Apple> list = Arrays.asList(
new Apple("green", 150),
new Apple("yellow", 120),
new Apple("green", 170));
List<Apple> greenList = list.stream().filter(a -> a.getColor().equals("green")).collect(Collectors.toList());
Optional.of(greenList).ifPresent(System.out::println);
//[Apple{color='green', weight=150}, Apple{color='green', weight=170}]
}
分组
根据颜色分组
传统做法
/**
* 按颜色分组
* @param apples
* @return
*/
private static Map<String,List<Apple>> groupByNomal(List<Apple> apples){
Map<String,List<Apple>> map = new HashMap<>();
for (Apple apple : apples) {
List<Apple> list = map.get(apple.getColor());
if(list==null){
list=new ArrayList<>();
map.put(apple.getColor(),list);
}
list.add(apple);
}
return map;
}
Optional.of(groupByNomal(list)).ifPresent(System.out::println);
//{green=[Apple{color='green', weight=150}, Apple{color='green', weight=170}],
// yellow=[Apple{color='yellow', weight=120}]}
lamda 函数式编程
private static Map<String, List<Apple>> groupByFunction(List<Apple> apples) {
Map<String, List<Apple>> map = new HashMap<>();
apples.parallelStream().forEach(a -> {
List<Apple> colorList = Optional.ofNullable(map.get(a.getColor())).orElseGet(() -> {
List<Apple> list = new ArrayList<>();
map.put(a.getColor(), list);
return list;
});
colorList.add(a);
});
// map=null; (Variable used in lambda expression should be final or effectively final)
return map;
}
lambda中使用外层的变量,不能在lamdba表达式中修改其值,外层变量可以不是final类型的,但是绝对不可以在lambda表达式中修改外层变量的值。(Variable used in lambda expression should be final or effectively final)
Optional.ofNullable(groupByFunction(list)).ifPresent(System.out::println);
Collector的方式
private static Map<String, List<Apple>> groupByCollector(List<Apple> apples) {
return apples.parallelStream().collect(groupingBy(Apple::getColor));
}
Optional.ofNullable(groupByCollector(list)).ifPresent(System.out::println);
很快捷
Collector使用方法
公共类
Dish
public class Dish {
private final String name;
private final boolean vegetarian;
private final int calories;
private final Type type;
public Dish(String name, boolean vegetarian, int calories, Type type) {
this.name = name;
this.vegetarian = vegetarian;
this.calories = calories;
this.type = type;
}
public String getName() {
return name;
}
public boolean isVegetarian() {
return vegetarian;
}
public int getCalories() {
return calories;
}
public Type getType() {
return type;
}
public enum Type {MEAT, FISH, OTHER}
@Override
public String toString() {
return "Dish{" +
"name='" + name + '\'' +
", vegetarian=" + vegetarian +
", calories=" + calories +
", type=" + type +
'}';
}
}
初始化数据
public static List<Dish> menu = Arrays.asList(
new Dish("pork", false, 800, Dish.Type.MEAT),
new Dish("beef", false, 700, Dish.Type.MEAT),
new Dish("chicken", false, 400, Dish.Type.MEAT),
new Dish("french fries", true, 530, Dish.Type.OTHER),
new Dish("rice", true, 350, Dish.Type.OTHER),
new Dish("season fruit", true, 120, Dish.Type.OTHER),
new Dish("pizza", true, 550, Dish.Type.OTHER),
new Dish("prawns", false, 300, Dish.Type.FISH),
new Dish("salmon", false, 450, Dish.Type.FISH));
求卡路里的平均值
Collectors.averagingDouble/ Int/ Long
private static void testAveragingDouble() {
System.out.println("testAveragingDouble");
//求 平均数 返回 double
Optional.ofNullable(menu.stream().collect(Collectors.averagingDouble(Dish::getCalories)))
.ifPresent(System.out::println);
}
private static void testAveragingInt() {
System.out.println("testAveragingInt");
Optional.ofNullable(menu.stream().collect(Collectors.averagingInt(Dish::getCalories)))
.ifPresent(System.out::println);
}
private static void testAveragingLong() {
System.out.println("testAveragingLong");
Optional.ofNullable(menu.stream().collect(Collectors.averagingLong(Dish::getCalories)))
.ifPresent(System.out::println);
}
test
public static void main(String[] args) {
testAveragingDouble();
testAveragingInt();
testAveragingLong();
}
java.util.stream.Collectors#averagingDouble 源码
public static <T> Collector<T, ?, Double>
averagingDouble(ToDoubleFunction<? super T> mapper) { //ToDoubleFunction返回double类型
/*
* In the arrays allocated for the collect operation, index 0
* holds the high-order bits of the running sum, index 1 holds
* the low-order bits of the sum computed via compensated
* summation, and index 2 holds the number of values seen.
*/
return new CollectorImpl<>(
() -> new double[4],
(a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);},
(a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]),
CH_NOID);
}
java.util.function.ToDoubleFunction
给任意一个参数返回一个double类型数据
@FunctionalInterface
public interface ToDoubleFunction<T> {
/**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
double applyAsDouble(T value);
}
Collectors.collectingAndThen 修饰平均值结果 及 禁止修改
private static void testCollectingAndThen() {
System.out.println("testCollectingAndThen");
String collect = menu.stream().collect(Collectors.collectingAndThen(
Collectors.averagingInt(Dish::getCalories), a -> "The Average Calories is->" + a));
Optional.ofNullable(collect).ifPresent(System.out::println);
}
返回的东西会被修改怎么办
Collections::unmodifiableList
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
实际上就是 将返回的结果 用 Collections.unmodifiableList(list);这个方法包装后再返回
List dishes = Collections.unmodifiableList(list);
private static void testCollectingAndThen() {
System.out.println("testCollectingAndThen");
String collect = menu.stream().collect(Collectors.collectingAndThen(
Collectors.averagingInt(Dish::getCalories), a -> "The Average Calories is->" + a));
Optional.ofNullable(collect).ifPresent(System.out::println);
List<Dish> list = menu.stream().filter(d -> d.getType().equals(Dish.Type.MEAT))
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
list.add(new Dish("", false, 100, Dish.Type.OTHER));
System.out.println(list);
}
统计返回结果数 Collectors.counting()
private static void testCounting() {
System.out.println("testCounting");
Optional.of(menu.stream().collect(
Collectors.counting()
)).ifPresent(System.out::println);//9
}
分组
按类型分组 Collectors.groupingBy(Dish::getType))
private static void testGroupingByFunction() {
System.out.println("testGroupingByFunction");
Map<Dish.Type, List<Dish>> collect = menu.stream().collect(
Collectors.groupingBy(Dish::getType)
);
Optional.of(collect).ifPresent(System.out::println);
}
分类计算总数
private static void testGroupingByFunctionAndCollector() {
System.out.println("testGroupingByFunctionAndCollector");
Map<Dish.Type, Long> collect = menu.stream().collect(
Collectors.groupingBy(
Dish::getType,
Collectors.counting()
));
Optional.of(collect).ifPresent(System.out::println);
}
分类求卡路里平均值
private static void testGroupingByFunctionAndCollector() {
System.out.println("testGroupingByFunctionAndCollector");
Map<Dish.Type, Double> collect = menu.stream().collect(
Collectors.groupingBy(
Dish::getType,
Collectors.averagingInt(Dish::getCalories)
));
Optional.of(collect).ifPresent(System.out::println);
}
分类求卡路里平均值 treeMap
private static void testGroupingByFunctionAndSupplierAndCollector() {
System.out.println("testGroupingByFunctionAndSupplierAndCollector");
Map<Dish.Type, Double> map = menu.stream().collect(
Collectors.groupingBy(Dish::getType,
TreeMap::new,
Collectors.averagingInt(Dish::getCalories)
));
Optional.of(map.getClass()).ifPresent(System.out::println);
Optional.of(map).ifPresent(System.out::println);
}
Collectors.summarizingInt 求多个常规聚合值
private static void testSummarizingInt() {
System.out.println("testSummarizingInt");
IntSummaryStatistics result = menu.stream().collect(
Collectors.summarizingInt(Dish::getCalories)
);
Optional.of(result).ifPresent(System.out::println);
}