前言
Stream 流?第一眼看起来以为是jdk1.8对I/O流的一个扩充,后来仔细看并不是的。
有没有发现数据库做一些过滤、聚合和排序很方便,我们在代码中要求某个集合的最大值或者求平均数还要自己遍历特别麻烦,其实数据库是有自己的内嵌算法来进行这些操作的,那么java中有没有这样的工具类来避免程序员这样麻烦的操作,而且有时候集合比较大需要并行操作来保证效率,我们需要保证并行不出错也是比较麻烦的,所以Stream应运而上。
Stream服务于阵列、集合、生成函数、I / O通道等,用于对一堆数据进行filter, map, limit, reduced, find, match等聚合查询操作,避免了我们自己遍历去实现。Stream就相当于“集合”的补充,“集合”负责存储,Stream负责带有条件的对这些数据进行查询。
Stream的方法
Stream的构造方法
常见几种
// 1. Individual values
Stream stream = Stream.of("a", "b", "c");
// 2. Arrays
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 3. Collections
List<String> list = Arrays.asList(strArray);
stream = list.stream();
Stream的操作方法
Stream大致分为两种,一个是流转换结果还是stream称之为Intermediate中间操作,一个是得到结果不是stream称之为Terminal。
Intermediate类方法
distinct
List<String> strings0 = Arrays.asList("b", "b", "bc", "fg", "bc", "", "jkl"); System.out.println("distinct:"+strings0.stream().distinct().collect(Collectors.toList()));
filter
对数据源进行过滤相当于sql语句中的where
List<Integer> integerList=Arrays.asList(1,2,3,8,9,4,15,12,18,17);
System.out.println("filter:"+integerList.stream().filter(i->i%2==0).collect(Collectors.toList()));
flatMap/Map
flatMap
将流中的每个元素按照映射函数进行处理,映射函数返回的是stream,所以最终的结果是映射函数每次返回结果的组合,还一个流,有什么用呢?看看下面的例子。
String [] strs1 = {"a","b","c"};
String [] strs2 = {"d","e","f"};
String [] strs3 = {"a","g","h"};
Arrays.asList(strs1,strs2,strs3).stream().forEach(System.out::print);
System.out.println();
Arrays.asList(strs1,strs2,strs3).stream().flatMap(strings -> Stream.of(strings)).forEach(System.out::print);
/*output:
*[Ljava.lang.String;@433c675d[Ljava.lang.String;@3f91beef[Ljava.lang.String;@1a6c5a9e
*abcdefagh
*/
可以发现对流中的元素进行处理,流中的元素如果不是基本数据就不能进行处理(复杂数据类型并没有转换成流),可以利用flatMap来对复杂元素进行转换,然后会拼接成一个流进行处理。
Map
对流内的元素用映射函数进行处理(数据的转换、“计算”等),返回的结果还是流。
List<Integer> integerList=Arrays.asList(1,2,3,8,9,4,15,12,128,17);
integerList.stream().map(i-> i+1).forEach(System.out::println);
peek
返回一个由该流元素组成的流。另外,在生成的流中使用元素时,对每个元素执行相应的操作。
Stream.of("one", "two", "three", "four")
.peek(e -> System.out.println("Peeked value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
sorted
对元素进行排序,可以自己设定排序规则。
List<Integer> integerList=Arrays.asList(1,2,3,8,9,4,15,12,128,17);
integerList.stream().sorted().peek(e -> System.out.print(e+" ")).collect(Collectors.toList());
Terminal类方法
Match
返回流内匹配该谓词的所有元素。
示例:
List<Integer> integerList=Arrays.asList(1,2,3,8,9,4,15,12,18,17);
System.out.println("all element is greater 10 ?"+integerList.stream().allMatch(integer -> integer>10));
System.out.println("any element is greater 10 ?"+integerList.stream().anyMatch(integer -> integer>10));
System.out.println("no element is greater 10 ?"+integerList.stream().noneMatch(integer -> integer>10));
结果:
all element is greater 10 ?false
any element is greater 10 ?false
no element is greater 10 ?true
Collect
<R,A> R collect(Collector<? super T,A,R> collector)
使用收集器对这个流的元素执行一个可变的缩减操作。收集器封装用于收集(供应商、BiConsumer、BiConsumer)的参数的函数,允许重用收集策略和收集操作的组合,比如多级别分组或分区。
这是个Terminal操作,会把流的操作结果放进Collector里面,可以是集合(map、set、list)。
具体操作还得看Collectors,下面给出几种常见的用法。
示例:
流还原list
List<String> strings0 = Arrays.asList("b", "b", "bc", "fg", "bc", "", "jkl");
List<String> strings1=strings0.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
分组
List<Integer> integerList=Arrays.asList(1,2,3,8,9,4,15,12,18,17);
Map<Boolean, List<Integer>> collectGroup = integerList.stream().collect(Collectors.groupingBy(it -> it > 9));
System.out.println("collectGroup:"+collectGroup);
求总数、和、最小、平均、最大
List<Integer> integerList=Arrays.asList(1,2,3,8,9,4,15,12,18,17);
IntSummaryStatistics summarizing = integerList.stream().collect(Collectors.summarizingInt(i -> i));
System.out.println(summarizing);
/*
*output:IntSummaryStatistics{count=10, sum=89, min=1, average=8.900000, max=18}
*/
把结果连接成字符串
List<String> strings0 = Arrays.asList("b", "b", "bc", "fg", "bc", "", "jkl");
System.out.println(strings0.stream().collect(Collectors.joining(" and ")));
count
示例
List<String> strings0 = Arrays.asList("b", "b", "bc", "fg", "bc", "", "jkl");
System.out.println("count:"+strings0.stream().filter(string -> !string.isEmpty()).count());
返回Optional类型的
返回Optional类型的有 findAny、max/min、findFirst等,用法顾名思义。
List<Integer> integerList=Arrays.asList(1,2,3,8,9,4,15,12,128,17);
System.out.println("findany:"+integerList.stream().findAny().get());
System.out.println("findFirst:"+integerList.stream().findFirst().get());
System.out.println("max:"+integerList.stream().max((i,j) -> i.compareTo(j)).get());
System.out.println("min:"+integerList.stream().min((i,j) -> i.compareTo(j)).get());
reduce
api上说:“使用一个关联累积函数,对该流元素做一个减少的操作,如果有的话返回操作的最后的值。”,是不是很晦涩?我也不知写文档的人为啥表述成这样,看的真心累。
大概的意思是按照一定的算法对流内元素进行类似“计算”一类的操作,返回一个“计算”后的结果,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。
List<Integer> integerList=Arrays.asList(1,2,3,8,9,4,15,12,128,17);
System.out.println("reduce sum:"+integerList.stream().reduce((i,j)->i+j).get());
System.out.println("reduce max:"+integerList.stream().reduce(Integer::max).get());
List<String> strings0 = Arrays.asList("b", "b", "bc", "fg", "bc", "", "jkl");
System.out.println("reduce string concat (有初始值):"+strings0.stream().reduce("",String::concat));
并行流
集合支持 parallelStream() 方法来创建元素的并行流。或者你可以在已存在的
数据流上调用衔接方法 parallel() ,将串行流转换为并行流。
Arrays.asList("a1", "a2", "b1", "c2", "c1")
.parallelStream()
.filter(s -> {
System.out.format("filter: %s [%s]\n",
s, Thread.currentThread().getName());
return true;
})
.map(s -> {
System.out.format("map: %s [%s]\n",
s, Thread.currentThread().getName());
return s.toUpperCase();
})
.forEach(s -> System.out.format("forEach: %s [%s]\n",
s, Thread.currentThread().getName()));
/*output:
filter: b1 [main]
map: b1 [main]
forEach: B1 [main]
filter: c1 [main]
map: c1 [main]
forEach: C1 [main]
filter: c2 [main]
map: c2 [main]
forEach: C2 [main]
filter: a1 [main]
map: a1 [main]
forEach: A1 [main]
filter: a2 [ForkJoinPool.commonPool-worker-1]
map: a2 [ForkJoinPool.commonPool-worker-1]
forEach: A2 [ForkJoinPool.commonPool-worker-1]
*/