Stream是一个流,在java.util.Stream包路径下,主要作用就是对集合数据进行查找过滤等操作,一种高效且易用的数据处理方式。

Stream流的创建:此处列举3种常用方法

//1. 通过 java.util.Collection.stream() 方法
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream  
Stream<String> parallelStream = list.parallelStream();  //创建并行流

//2. 通过java.util.Arrays.stream(T[] array)方法
int []arr={1,34,2,54,56,34};
IntStream stream = Arrays.stream(arr)  

//3. 通过Stream的静态方法
Stream<Integer> stream = Stream.of("11","22","33")

在Stream流上的操作,可以分成两种:Intermediate(中间操作)Terminal(终止操作)。中间操作的返回结果都是Stream,故可以多个中间操作叠加;终止操作用于返回我们最终需要的数据,只能有一个终止操作。
中间操作:将原始的Stream转换成另外一个Stream;如filter返回的是过滤后的Stream。
终止操作:产生的是一个结果或者其它的复合操作;如count或者forEach操作。

中间操作
filter :用于通过一定的规则,将符合条件的元素过滤出来到新的流中
map :映射,元素一对一转换,将流中的每一个元素转换成其他形式或提取出某条信息
sorted :用于对流中元素进行排序
concat :合并两个流
distinct:将流中元素去重
limit :限制从流中获得前n个数据
skip:跳过流中前n个数据

终端操作:
max : 流中元素的最大值
min : 流中元素的最小值
count : 流中元素的个数
findFirst : 返回当前流中第一个元素
forEach : 对所有元素进行遍历处理,无返回值
reduce : 根据一定的规则将Stream中的元素进行计算后返回一个唯一的值。

  • reduce是一种聚合操作,聚合的含义就是将多个值经过特定计算之后得到单个值,返回的结果是一个Optional对象
  • 常见的有count 、sum 、avg 、max 、min 等函数就是一种聚合操作
  • 一个参数的reduce:Optionalreduce(BinaryOperatoraccumulator); 可接收(result,item)->{…} 。
    返回值:返回Optional对象,由于结果存在空指针的情况(当集合为空时)因此需要使用Optional。
//将数组进行累加求和
//由于返回的是 Optional ,因此需要get()取出值。
List list = Lists.newArrayList(1,2,3,4,5);
Integer sum = list.stream().reduce((result,item) -> result+item).get();

//第一个参数 result :初始值为集合中的第一个元素,后面为每次的累加计算结果 ;
//第二个参数 item :遍历的集合中的每一个元素(从第二个元素开始,第一个被result使用了)。
  • 两个参数的reduce:T reduce(T identity, BinaryOperatoraccumulator)
//计算数的总和
List<Integer >list = Arrays.asList(1,2,3,4,5);
Integer reduce = list.stream().reduce(0, Integer::sum );

//参数1:T identity 为一个初始值(默认值) ,当集合为空时,就返回这个默认值,当集合不为空时,该值也会参与计算;
//参数2:BinaryOperatoraccumulator 这个与一个参数的reduce相同。
//返回值:并非 Optional,由于有默认值 identity ,因此计算结果不存在空指针的情况。

collect(Collector):

  • toList, toSet, toMap, count, averagingInt, summingInt, maxBy, joining(字符串元素拼接)
  • toMap(fun1, fun2)/toConcurrentMap,两个fun用来产生键和值,若值为元素本身,则fun2为Function.identity()
  • groupingBy(fun): 分组,生成Map,键是fun函数结果
    partitioningBy(fun):分区(两类) 键是true/false,当fun是断言函数时用此方法,比groupingBy(fun)更高效
//选出能被2整除的数并返回成List/Set
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
	List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
	Set<Integer> set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet())

演示几个简单案例便于理解:

List<Integer> list = new ArrayList<>();
		list.add(10);
		list.add(10);
		list.add(3);
		list.add(9);
		list.add(33);
		list.add(-1);
		System.out.println("origin: "+ list);
	
	//对list中元素进行去重,排序,然后选取前面三个最小的数据
		List<Integer> collect1 = list.stream().distinct().sorted().limit(3).collect(Collectors.toList());
		System.out.println("对list中元素进行去重,排序,然后选取前面三个最小的数据: "+ collect1);
		//选出list中的最大值
		Integer max = list.stream().max(Integer::compareTo).get();
		System.out.println("选出list中的最大值" + max);
		//计算list中大于9的元素个数
		long count = list.stream().filter(x -> x > 9).count();
		System.out.println("计算list中大于9的元素个数" + count);
		
		//使用reduce聚合
		//求和方式1
		Integer sum1 = list.stream().reduce(Integer::sum).get();
		//求和方式2
		Integer sum2 = list.stream().reduce((x, y) -> x + y).get();
		//求和方式3,0是默认值,所以不存在为空的情况
		Integer sum3 = list.stream().reduce(0, (Integer::sum));
		System.out.println("计算总和方式1:" + sum1 + " 计算总和方式2:" + sum2 +" 计算总和方式3:" + sum3);

输出结果:

origin: [10, 10, 3, 9, 33, -1]
对list中元素进行去重,排序,然后选取前面三个最小的数据: [-1, 3, 9]
选出list中的最大值33
计算list中大于9的元素个数3
计算总和方式1:64 计算总和方式2:64 计算总和方式3:64

public class Student  implements Comparable{
		private Integer id;
		private String name;
		private Integer age;
		private Double score;
	//省略了set get constructor
}
		List<Student> stuList = new ArrayList<>();
		stuList.add(new Student(1,"jack",23,89.5));
		stuList.add(new Student(2,"jony",22,90.5));
		stuList.add(new Student(3,"Alice",22,87.1));
	
	//案例1:选出分数大于等于80分的学生,并获取所有学生的姓名name
	//map中可以使用对象.方法,或者类名引用
		List<String> names = stuList.stream().filter(stu -> stu.getScore() >= 80).map(Student::getName).collect(Collectors.toList());
		List<String> names2 = stuList.stream().filter(stu -> stu.getScore() >= 80).map(student -> student.getName()).collect(Collectors.toList());
		System.out.println("案例1:选出分数大于等于80分的学生,并获取所有学生的姓名name: " + names);
		System.out.println("案例1:选出分数大于等于80分的学生,并获取所有学生的姓名name: " + names2);

	//案例2:将所有学生按照分数排序,(默认升序,加reversed改为降序)
		List<Student> sortedStu = stuList.stream().sorted(Comparator.comparing(Student::getScore).reversed()).collect(Collectors.toList());
		System.out.println("案例2:将所有学生按照分数排序: " + sortedStu);

	//案例3:将所有学生的年龄age+1
		//1. 不改变原来学生集合
		List<Student> studentListNew = stuList.stream().map(student -> {
			Student studentNew = new Student(student.getId(), student.getName(), student.getAge() + 1,
							student.getScore());
			return studentNew;
		}).collect(Collectors.toList());
		System.out.println("befor: " + stuList.get(0).getName() + stuList.get(0).getAge());
		System.out.println("after: " + studentListNew.get(0).getName() + studentListNew.get(0).getAge());

		//2. 改变原来学生集合
		List<Student> studentListNew2 = stuList.stream().map(student -> {
			student.setAge(student.getAge() + 1);
			return student;
		}).collect(Collectors.toList());
		System.out.println("befor: " + stuList.get(0).getName() + stuList.get(0).getAge());
		System.out.println("after: " + studentListNew2.get(0).getName() + studentListNew2.get(0).getAge());
	}
	//案例4:计算所有学生中分数最高的一位
		Student maxScoreStu = stuList.stream().max(Comparator.comparing(Student::getScore)).get();
		System.out.println("所有学生中分数最高的一位: " + maxScoreStu);
		String maxScoreStuName = stuList.stream().max(Comparator.comparing(Student::getScore)).map(Student::getName).get();
		System.out.println("单独获取最高分学生的名字:" + maxScoreStuName);
	//案例5:使用reduce中的聚合
		Double sumDouble = stuList.stream().map(student -> student.getScore()).reduce(Double::sum).get();
		Double averageDouble = stuList.stream().mapToDouble(student -> student.getScore()).average().getAsDouble();
		Double maxDouble = stuList.stream().map(Student::getScore).reduce(Double::max).get();
		System.out.println("计算学生分数总和:" + sumDouble + " 计算平均分: " + averageDouble + " 计算最高分: " + maxDouble);

输出结果

案例1:选出分数大于等于80分的学生,并获取所有学生的姓名name: [jack, jony, Alice]
 案例1:选出分数大于等于80分的学生,并获取所有学生的姓名name: [jack, jony, Alice]
 案例2:将所有学生按照分数排序: [Student{id=2, name=‘jony’, age=22, score=90.5}, Student{id=1, name=‘jack’, age=23, score=89.5}, Student{id=3, name=‘Alice’, age=22, score=87.1}, Student{id=4, name=‘dack’, age=24, score=79.7}]
 操作1_befor: jack23
 操作1_after: jack24
 操作2_befor: jack24
 操作2_after: jack24
 所有学生中分数最高的一位: Student{id=2, name=‘jony’, age=23, score=90.5}
 单独获取最高分学生的名字:jony
 计算学生分数总和:346.8 计算平均分: 86.7 计算最高分: 90.5