介绍 Java8 Stream 中 Collectors.groupingBy()
的文章已经很多了,这里想记录一下该方法和 Collectors.mapping()
方法配合使用的一些案例。
一、准备
Student
实体类。
@Data
@AllArgsConstructor
public class Student {private String name;private int age;private int score;
}
- 初始化集合
static final List<Student> studentList = Arrays.asList(new Student("S1", 8, 80),new Student("S2", 8, 80),new Student("S3", 8, 85),new Student("S4", 8, 90),new Student("S5", 9, 95),new Student("S6", 9, 85),new Student("S7", 9, 90)
);
二、按 age 分组 + name 集合
public static void main(String[] args) {Map<Integer, Set<String>> result = studentList.stream().collect(Collectors.groupingBy(Student::getAge, Collectors.mapping(Student::getName, Collectors.toSet())));System.out.println(result);
}
输出:
{8=[S3, S4, S1, S2],9=[S5, S6, S7]
}
三、按 age 分组 + score 最大值
public static void main(String[] args) {Map<Integer, Double> result = studentList.stream().collect(Collectors.groupingBy(Student::getAge,Collectors.mapping(Student::getScore, Collectors.maxBy(Integer::compareTo))));System.out.println(result);
}
输出:
{8=Optional[90],9=Optional[95]
}
Collectors.summingInt()分组求和
如何用Streamapi进行分组求和,可以使用Collectors.groupby(, Collectors.summingInt())来进行分组求和。
public class Test {public static void main(String[] args) {Student student1 = new Student(1, 1);Student student2 = new Student(1, 1);Student student3 = new Student(2, 2);Student student4 = new Student(2, 3);Student student5 = new Student(3, 3);Student student6 = new Student(3, 4);Student student7 = new Student(4, 1);List<Student> list = Arrays.asList(student1, student2, student3, student4, student5, student6, student7);Map<Integer, Integer> collect = list.stream().collect(Collectors.groupingBy(Student::getId, Collectors.summingInt(Student::getScore)));System.out.println(collect);}
}class Student{private Integer id;private Integer score;
}
Collectors.summingDouble()
Java 8
流的新类java.util.stream.Collectors
实现了java.util.stream.Collector
接口,同时又提供了大量的方法对流 (stream
) 的元素执行map
and
reduce
操作,或者统计操作。
Collectors.summingDouble()
方法将流中的所有元素视为 Double
类型,并计算所有元素的总和 ( sum )
summingDoubleExample代码
@Test
public void summingDoubleExample() {List<Double> list = Arrays.asList(1.1, 2.2, 3.3, 4.4);Double sum = list.stream().collect(Collectors.summingDouble(i -> {System.out.println("i -> " + i);return i;}));System.out.println(sum);
}
summingLongExample结果
i -> 1.1
i -> 1.1
i -> 2.2
i -> 2.2
i -> 3.3
i -> 3.3
i -> 4.4
i -> 4.4
11.0
运行结果: 结果显示计算平均值时为什么会打印两遍其中的值?
- 如果在方法体中操作全局变量岂不是操作两遍?? 这不是坑么
- 如果在方法体中做复杂操作,岂不是两倍??? 巨坑阿
- 如果在方法体中做判断,判断后改动状态值,改两遍!!
- ……
- 用我智慧的大脑一想……没得玩了
注意:
-
定义
List
中,也就是生成stream
流中的参数要进行类型声明,如果不明确类型,里面还要进行强制转换 -
由于是
Double
,值的上限是很不明显的,如果想要溢出是很难的,除非有超级大的计算量-
@Test public void summingDoubleExample() {System.out.println(Double.MAX_VALUE); } //结果为:1.7976931348623157E308 何其之大
-
-
这就使
Double
的优势很明显了,其与summingLong
|summingInt
明显不同 -
劣势还是很明显的,函数体中计算两次,容易导致其他错误。