阅读量:0
通过一个具体的例子来说明 Collectors.groupingBy
的用法。假设我们有一个学生列表,每个学生有姓名、年级和分数三个属性,我们希望按照年级对学生进行分组,并且在分组后计算每个年级学生的平均分数。
首先,定义学生类 Student
:
public class Student { private String name; private int grade; private double score; // 构造函数、getter和setter省略 public Student(String name, int grade, double score) { this.name = name; this.grade = grade; this.score = score; } public String getName() { return name; } public int getGrade() { return grade; } public double getScore() { return score; } }
然后,创建一个学生列表并进行操作:
import java.util.*; import java.util.stream.*; import static java.util.stream.Collectors.*; public class GroupingExample { public static void main(String[] args) { List<Student> students = Arrays.asList( new Student("Alice", 10, 82.5), new Student("Bob", 10, 90.0), new Student("Charlie", 11, 88.0), new Student("Diana", 11, 95.5) ); // 按年级分组 Map<Integer, List<Student>> studentsByGrade = students.stream() .collect(groupingBy(Student::getGrade)); System.out.println("Students grouped by grade: " + studentsByGrade); // 按年级分组,并计算每个年级的平均分 Map<Integer, Double> averageScoreByGrade = students.stream() .collect(groupingBy(Student::getGrade, averagingDouble(Student::getScore))); System.out.println("Average score by grade: " + averageScoreByGrade); // 按年级分组,然后统计每个年级的学生人数 Map<Integer, Long> countByGrade = students.stream() .collect(groupingBy(Student::getGrade, counting())); System.out.println("Number of students in each grade: " + countByGrade); } }
在这个例子中,我们首先按照学生的年级进行分组,然后在分组的基础上进行了两个进一步的操作:
- 计算每个年级学生的平均分数。
- 统计每个年级的学生人数。
输出结果如下:
Students grouped by grade: {10=[Alice, Bob], 11=[Charlie, Diana]} Average score by grade: {10=86.25, 11=91.75} Number of students in each grade: {10=2, 11=2}
Java Stream API 提供了一种高效且表达式丰富的方式来处理数据集合。默认情况下,Stream 操作是顺序执行的。但是,Java 也提供了并行流(parallelStream
),通过这种方式可以实现对数据集合的并发处理。
要创建一个并行流,你可以通过集合的 parallelStream()
方法,或者将一个现有的流通过 parallel()
方法转换为并行流。并行流利用了Java的Fork/Join
框架来拆分任务并使用多个线程进行处理,这样可以加速处理过程,特别是在处理大数据集合时。
示例:顺序流
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1"); myList.stream() .filter(s -> s.startsWith("c")) .map(String::toUpperCase) .sorted() .forEach(System.out::println); // 输出顺序处理的结果
示例:并行流
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1"); myList.parallelStream() .filter(s -> s.startsWith("c")) .map(String::toUpperCase) .sorted() .forEach(System.out::println); // 输出并行处理的结果,可能与顺序流的输出顺序不同
需要注意的是,并行流并不总是比顺序流快。并行处理会引入线程管理的开销,如果处理的数据量不大,或者每个元素的处理时间非常短,那么这种开销可能会导致并行流的性能低于顺序流。此外,并行流的操作可能会改变操作的结果,特别是在使用有状态的中间操作(如sorted()
、distinct()
等)时,因此在使用并行流时需要特别注意。