文章目录
一、什么是Stream
Stream是java8新增的类,同时也是新加的一个特性。它的作用是将数据以流的形式处理,该类提供了流操作的方法,数据从源流入,中间可以经过这些操作对数据流做出处理,最后流出,Stream就像一个管道一样,数据是流经管道中的水。流经Stream的这些数据来源可以是数组,集合,甚至是一个对象。
在Stream里面,数据经过的操作分为两种:
- 中间操作:对数据流做一些处理,之后以流的形式流出,中间操作后面还可以有其他操作,中间操作又可以细分为无状态(Stateless)和有状态的(Stateful),无状态表示元素的处理不受之前元素的影响;有状态表示该操作只有拿到所有元素之后才能继续下去;
- 终端操作:是本次流处理的最后一个操作,每个流只能进行一次终端操作,终端操作又可以细分为短路操作和非短路操作,短路操作是指遇到符合条件的元素就可以终止处理返回最终结果,非短路操作是指必须处理所有元素才能得到最终结果。
下图罗列了Stream的常用操作:
Stream还有以下特性:
- Stream在执行上图这些操作的时候,不会修改数据源的数据,如果数据源是一个数组,执行一系列操作后,数组中的数据保持原样不变;
- 如果Stream操作中没有终端操作,那么不会触发中间操作对数据处理;
- Stream对象一旦执行过终端操作,就不能再次使用,只能新建流;
- 流可以单线程或者多线程处理数据,分别称为顺序流和并行流。
二、创建Stream
1、Stream静态方法创建
Stream提供了generate(),concat(),empty(),iterate(),of()方法创建Stream对象。
//generate() 要求入参是Supplier接口实现类,这里使用了方法引用,limit方法表示只取前五个数字
Stream s1=Stream.generate(Math::random).limit(5);
s1.forEach(x-> {
System.out.print(x+",");
return;
});
System.out.println('\n');
//of的入参要求是一个数组
Stream s2=Stream.of(1,2,3,4,5);
s2.forEach(x-> {
System.out.print(x+",");
return;
});
System.out.println('\n');
//iterate方法的第一个入参是种子,第二个入参表示从种子产生后续元素的规则
Stream s3=Stream.iterate(1,i->(i+1)).limit(5);
s3.forEach(x-> {
System.out.print(x+",");
return;
});
执行结果为:
0.41496598483096414,0.0688991791546536,0.22740053512262426,0.003628221833255507,0.8909583300521023,
1,2,3,4,5,
1,2,3,4,5,
concat()方法用于将两个Stream对象结合起来形成一个流对象。
empty()方法用于产生一个空流,该流里面没有任何元素。
2、Arrays.stream()创建流
Integer[] a=new Integer[5];
a[0]=1;a[1]=2;a[2]=3;a[3]=4;a[4]=5;
Stream s2=Arrays.stream(a);
s2.forEach(x-> {
System.out.print(x+",");
return;
});
运行结果:
1,2,3,4,5,
Arrays.stream()也可以创建IntStream、LongStream等流对象,这些流对象是java提供的专门处理int、long等类型的,它们对int、long等类型做了针对性的优化处理。注意IntStream、LongStream与Stream没有继承关系。
3、Collection.stream()创建流
Collection.stream()用于创建顺序流,Collection还提供了parallelStream()可以创建并行流。
List list=new ArrayList<>();
list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);
Stream s2=list.stream();
s2.forEach(x-> {
System.out.print(x+",");
return;
});
运行结果:
1,2,3,4,5,
三、Stream操作
下面先介绍终端操作,之后介绍中间操作。
1、foreach()遍历
foreach()上面已经展示过了,它遍历流中的每个元素,对每个元素使用入参对象处理。
2、find()查找/match()匹配
List<Integer> list=new ArrayList<>();
list.add(5);list.add(4);list.add(1);list.add(3);list.add(2);
Optional o1=list.stream().filter(x->(x<=3)).findAny();//返回流中任意一个元素
System.out.println(o1.get());
Optional o2=list.stream().filter(x->(x<=3)).findFirst();//返回流中第一个元素
System.out.println(o2.get());
System.out.println(list.stream().allMatch(x->(x<=3)));//检查流中所有的元素是否都符合条件要求
System.out.println(list.stream().anyMatch(x->(x<=3)));//检查流中是否有符合条件要求的元素
System.out.println(list.stream().noneMatch(x->(x<=3)));//检查流中所有的元素是否都不符合条件要求
运行结果:
1
1
false
true
false
3、reduce()规约
规约相当于缩减,将流中的多个元素通过某种操作缩减为一个元素。
Stream提供了入参三个重载方法:
Optional<T> reduce(BinaryOperator<T> accumulator);
T reduce(T identity, BinaryOperator<T> accumulator);
<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner);
先演示一下如何使用这些方法。
List<Integer> list=new ArrayList<>();
list.add(5);list.add(4);list.add(1);list.add(3);list.add(2);
//元素求和
Optional<Integer> o1=list.stream().reduce(Integer::sum);
System.out.println(o1.get());
//元素求最大值
Optional<Integer> o2=list.