还不清楚Steam流的用法的,可以先看这篇Stream流(Stream,Lambda)
我们以下的例子都是基于这个学生类Student来操作,下面是学生类Student的代码
学生属性有:编号,名字,年龄,数学成绩,语文成绩,重写toString方法,重写equals和hashCode方法
package com.TestStream;
/**
* @author 林高禄
* @create 2020-06-04-16:47
*/
public class Student {
private Integer no;
private String name;
private Integer age;
private Double mathScore;
private Double chineseScore;
public Student(Integer no, String name, Integer age, Double mathScore, Double chineseScore) {
this.no = no;
this.name = name;
this.age = age;
this.mathScore = mathScore;
this.chineseScore = chineseScore;
}
public Integer getNo() {
return no;
}
public void setNo(Integer no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Double getMathScore() {
return mathScore;
}
public void setMathScore(Double mathScore) {
this.mathScore = mathScore;
}
public Double getChineseScore() {
return chineseScore;
}
public void setChineseScore(Double chineseScore) {
this.chineseScore = chineseScore;
}
@Override
public String toString() {
return "Student{" +
"no=" + no +
", name='" + name + '\'' +
", age=" + age +
", mathScore=" + mathScore +
", chineseScore=" + chineseScore +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return no != null ? no.equals(student.no) : student.no == null;
}
@Override
public int hashCode() {
return no != null ? no.hashCode() : 0;
}
}
为了方便代码的复用,就弄了一个学生的工具类StudentUtil2,来生成学生的列表,代码为
package com.TestStream;
import java.util.ArrayList;
import java.util.List;
/**
* @author 林高禄
* @create 2020-06-04-17:18
*/
public class StudentUtil2 {
/**
* 生成指定的学生类的列表,用于测试
*
* @return List<Student>
*/
public static List<Student> createStudentList() {
List<Student> studentList = new ArrayList<>();
studentList.add(new Student(1, "林高禄", 20, 90.5, 90.5));
studentList.add(new Student(11, "林高禄", 20, 90.5, 90.5));
studentList.add(new Student(1, "1林高禄", 20, 90.5, 90.5));
studentList.add(new Student(2, "林高禄", 10, 80.0, 90.0));
studentList.add(new Student(1, "林高禄", 30, 90.5, 90.0));
studentList.add(new Student(1, "陈文文", 10, 100.0, 90.0));
studentList.add(new Student(2, "陈文文", 20, 90.0, 70.0));
studentList.add(new Student(1, "蔡金鑫", 30, 80.0, 90.0));
return studentList;
}
}
下面我们就通过例子来演示Stream流的高级用法
一、分组求和—collect
例子:求相同姓名的学生的年龄之和(姓名组合)
package com.TestStream;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author 林高禄
* @create 2020-06-09-9:29
*/
public class Demo2 {
public static void main(String[] args) {
List<Student> studentList = StudentUtil2.createStudentList();
// 通过姓名分组,姓名为key,相同姓名的学生为列表
Map<String, List<Student>> collect = studentList.stream().collect(Collectors.groupingBy(Student::getName, Collectors.toList()));
// collect的数据为
System.out.println("collect的数据为:");
collect.forEach((key,list)-> {
System.out.println("key:"+key);
list.forEach(System.out::println);
});
// 分组后的年龄和为
System.out.println("分组后的年龄和为:");
collect.forEach((key,list)-> System.out.println("key:"+key+",年龄和"+list.stream().mapToInt(Student::getAge).sum()));
}
}
运行输出:
collect的数据为:
key:陈文文
Student{no=1, name='陈文文', age=10, mathScore=100.0, chineseScore=90.0}
Student{no=2, name='陈文文', age=20, mathScore=90.0, chineseScore=70.0}
key:林高禄
Student{no=1, name='林高禄', age=20, mathScore=90.5, chineseScore=90.5}
Student{no=11, name='林高禄', age=20, mathScore=90.5, chineseScore=90.5}
Student{no=2, name='林高禄', age=10, mathScore=80.0, chineseScore=90.0}
Student{no=1, name='林高禄', age=30, mathScore=90.5, chineseScore=90.0}
key:1林高禄
Student{no=1, name='1林高禄', age=20, mathScore=90.5, chineseScore=90.5}
key:蔡金鑫
Student{no=1, name='蔡金鑫', age=30, mathScore=80.0, chineseScore=90.0}
分组后的年龄和为:
key:陈文文,年龄和30
key:林高禄,年龄和80
key:1林高禄,年龄和20
key:蔡金鑫,年龄和30
例子:求相同姓名和相同编号的学生的年龄之和(姓名——编号组合)
package com.TestStream;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author 林高禄
* @create 2020-06-09-9:41
*/
public class Demo3 {
public static void main(String[] args) {
List<Student> studentList = StudentUtil2.createStudentList();
// 通过combination返回的字符串分组,为key,相同的学生为列表
Map<String, List<Student>> collect = studentList.stream().collect(Collectors.groupingBy(Demo3::combination, Collectors.toList()));
// 分组后的年龄和为
System.out.println("分组后的年龄和为:");
collect.forEach((key,list)-> System.out.println("key:"+key+",年龄和"+list.stream().mapToInt(Student::getAge).sum()));
}
// 编号+姓名
private static String combination(Student s){
return s.getNo()+s.getName();
}
}
我们自写一个方法combination方便调用。编号+姓名组合
运行输出:
key:1陈文文,年龄和10
key:2陈文文,年龄和20
key:11林高禄,年龄和40
key:1蔡金鑫,年龄和30
key:1林高禄,年龄和50
key:2林高禄,年龄和10
发现了什么了没有,去看看我们的学生工具类生成的学生,有2个学生是这样的
studentList.add(new Student(11, "林高禄", 20, 90.5, 90.5));
studentList.add(new Student(1, "1林高禄", 20, 90.5, 90.5));
我们combination方法的组合方式,这2个学生都拼接成11林高禄,最终会当成同一个key,组合就错误,所以我们得把combination方法改造一下
package com.TestStream;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author 林高禄
* @create 2020-06-09-9:41
*/
public class Demo3 {
public static void main(String[] args) {
List<Student> studentList = StudentUtil2.createStudentList();
// 通过combination返回的字符串分组,为key,相同的学生为列表
Map<String, List<Student>> collect = studentList.stream().collect(Collectors.groupingBy(Demo3::combination, Collectors.toList()));
// 分组后的年龄和为
System.out.println("分组后的年龄和为:");
collect.forEach((key,list)-> System.out.println("key:"+key+",年龄和"+list.stream().mapToInt(Student::getAge).sum()));
}
// 编号+姓名
private static String combination(Student s){
return s.getNo()+s.getName()+s.getName();
}
}
运行输出:
分组后的年龄和为:
key:1林高禄林高禄,年龄和50
key:2林高禄林高禄,年龄和10
key:1陈文文陈文文,年龄和10
key:1蔡金鑫蔡金鑫,年龄和30
key:11林高禄林高禄,年龄和20
key:11林高禄1林高禄,年龄和20
key:2陈文文陈文文,年龄和20
这样的结果才是正确大的,因为只有名字形同,两个名字拼接才相同。只有编号相同,编号与两个名字拼接才相同。
二、组合排序—comparing—>thenComparing
例子:学生按编号排序,再按年龄排序
package com.TestStream;
import java.util.Comparator;
import java.util.List;
/**
* @author 林高禄
* @create 2020-06-09-9:41
*/
public class Demo4 {
public static void main(String[] args) {
List<Student> studentList = StudentUtil2.createStudentList();
System.out.println("第一种:直接排序");
studentList.sort(Comparator.comparing(Student::getNo).reversed().thenComparing(Comparator.comparing(Student::getAge).reversed()));
studentList.forEach(System.out::println);
System.out.println("第二种:用Stream排序");
studentList.stream()
.sorted(Comparator.comparing(Student::getNo).reversed().thenComparing(Comparator.comparing(Student::getAge).reversed()))
.forEach(System.out::println);
}
}
运行输出:
第一种:直接排序
Student{no=11, name='林高禄', age=20, mathScore=90.5, chineseScore=90.5}
Student{no=2, name='陈文文', age=20, mathScore=90.0, chineseScore=70.0}
Student{no=2, name='林高禄', age=10, mathScore=80.0, chineseScore=90.0}
Student{no=1, name='林高禄', age=30, mathScore=90.5, chineseScore=90.0}
Student{no=1, name='蔡金鑫', age=30, mathScore=80.0, chineseScore=90.0}
Student{no=1, name='林高禄', age=20, mathScore=90.5, chineseScore=90.5}
Student{no=1, name='1林高禄', age=20, mathScore=90.5, chineseScore=90.5}
Student{no=1, name='陈文文', age=10, mathScore=100.0, chineseScore=90.0}
第二种:用Stream排序
Student{no=11, name='林高禄', age=20, mathScore=90.5, chineseScore=90.5}
Student{no=2, name='陈文文', age=20, mathScore=90.0, chineseScore=70.0}
Student{no=2, name='林高禄', age=10, mathScore=80.0, chineseScore=90.0}
Student{no=1, name='林高禄', age=30, mathScore=90.5, chineseScore=90.0}
Student{no=1, name='蔡金鑫', age=30, mathScore=80.0, chineseScore=90.0}
Student{no=1, name='林高禄', age=20, mathScore=90.5, chineseScore=90.5}
Student{no=1, name='1林高禄', age=20, mathScore=90.5, chineseScore=90.5}
Student{no=1, name='陈文文', age=10, mathScore=100.0, chineseScore=90.0}
三、求极值—
summarizingLong
summarizingInt
summarizingDouble
例子:求出学生数学分数的各个值(最大,最小,平均,总数,个数)
package com.TestStream;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author 林高禄
* @create 2020-06-09-9:41
*/
public class Demo5 {
public static void main(String[] args) {
List<Student> studentList = StudentUtil2.createStudentList();
DoubleSummaryStatistics collect = studentList.stream().collect(Collectors.summarizingDouble(Student::getMathScore));
System.out.println(collect);
System.out.println("总分为:"+collect.getSum());
}
}
运行输出:
DoubleSummaryStatistics{count=8, sum=712.000000, min=80.000000, average=89.000000, max=100.000000}
总分为:712.0
综合例子:求相同年龄学生的语数总分的排名,倒序
package com.TestStream;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author 林高禄
* @create 2020-06-09-9:41
*/
public class Demo6 {
public static void main(String[] args) {
List<Student> studentList = StudentUtil2.createStudentList();
// 先按年龄分组求出极值对象
Map<Integer, DoubleSummaryStatistics> collect1 = studentList.stream().collect(Collectors.groupingBy(Student::getAge, Collectors.summarizingDouble(s -> s.getMathScore() + s.getChineseScore())));
List<DoubleSummaryStatistics> doubleSummaryStatisticsList = new ArrayList<>();
// 遍历map把极值对象放入集合
collect1.forEach((key,doubleSummaryStatistics)-> doubleSummaryStatisticsList.add(doubleSummaryStatistics));
// 极值对象排序输出
doubleSummaryStatisticsList.stream().sorted(Comparator.comparing(DoubleSummaryStatistics::getSum).reversed()).forEach(System.out::println);
System.out.println("------------");
// 极值对象排序输出总分
doubleSummaryStatisticsList.stream().sorted(Comparator.comparing(DoubleSummaryStatistics::getSum).reversed()).forEach(s-> System.out.println(s.getSum()));
}
}
运行输出:
DoubleSummaryStatistics{count=4, sum=703.000000, min=160.000000, average=175.750000, max=181.000000}
DoubleSummaryStatistics{count=2, sum=360.000000, min=170.000000, average=180.000000, max=190.000000}
DoubleSummaryStatistics{count=2, sum=350.500000, min=170.000000, average=175.250000, max=180.500000}
------------
703.0
360.0
350.5
Java Stream流高级应用:分组求和、组合排序与极值计算
本文介绍了Java Stream流的高级用法,包括使用collect进行分组求和(如按姓名、姓名编号组合),利用comparing和thenComparing进行组合排序,以及运用summarizing*方法求极值(如最大值、最小值、平均值)。通过具体的例子展示了这些操作在处理学生数据时的应用。
529

被折叠的 条评论
为什么被折叠?



