JAVA8新特性--集合流操作Stream

原文链接:https://blog.csdn.net/bluuusea/article/details/79967039

Stream类全路径为:java.util.stream.Stream
对Stream的描述,引用其他文章中觉得比较好的介绍:

Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。
即Stream的原理:

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
集合有两种方式生成流:
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。

并发模式(parallelStream)能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。java中也提供了多种并行处理的方式,看到一片文章对各几种并行的方式性能进行了测试,可以参考下:java中几种并行方式的性能分析。

Stream的的中间操作(intermediate)和最终操作(terminal)都包含哪些方法可以从类结构中看到:

上面截图基本包含了Strram的所有方法。

中间操作(intermediate)主要有以下方法(此类型的方法返回的都是Stream对象):
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

终端操作(terminal)主要有以下方法:
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

此处按照类结构(截图)中的方法的顺序(以下例子中使用了Lambda表达式及方法引用,不了解的请戳:Lambda介绍,方法引用),进行介绍:

filter:通过设置条件来过滤元素。
List<String> list = Arrays.asList("aaa","ddd","bbb","ccc","a2a","d2d","b2b","c2c","a3a","d3d","b3b","c3c");

list.stream()
.filter((s)->s.contains("a"))
.forEach(s -> System.out.println(s));
1
2
3
4
5
以上代码使用filter方法过滤出只包含”a”的元素,然后通过forEach将满足条件的元素遍历出来。输出如下:

aaa
a2a
a3a
map:就是将对应的元素使用给定方法进行转换。
list.stream()
.filter((s)->s.contains("a"))
.map((s)-> s + "---map")
.forEach(s -> System.out.println(s));
1
2
3
4
5
在filter的基础上,给每个元素后面添加字符串”—map”,输出如下:

aaa—map
a2a—map
a3a—map
mapToInt:和map方法进行一样的操作,但是转换函数必须返回int类型
mapToLong:和map方法进行一样的操作,但是转换函数必须返回long类型
mapToDouble:和map方法进行一样的操作,但是转换函数必须返回double类型
此处以mapToInt进行演示:
list.stream()
.filter((s)->s.contains("a"))
.mapToInt((s)-> s.hashCode())
.forEach(s -> System.out.println(s));
1
2
3
4
在filter的基础上,将每个元素转换为其hashCode。输出为:

96321
94864
94895
flatMap:如果流的元素为数组或者Collection,flatMap就是将每个Object[]元素或Collection<Object>元素都转换为Object元素,如下:
Stream<String[]> 转换为 Stream<String>
Stream<Set> 转换为 Stream<String>
Stream<List> 转换为 Stream<String>
Stream<List> 转换为 Stream<Object>
看下例子:

List<String[]> setList = new ArrayList<>();
setList.add(new String[]{"aa","bb"});
setList.add(new String[]{"cc","dd"});
setList.add(new String[]{"ee","ff"});
//使用map方法
setList.stream()
.map(s->Arrays.stream(s))
.forEach(s-> System.out.println("map==" + s));
//使用flatMap方法
setList.stream()
.flatMap(s->Arrays.stream(s))
.forEach(s-> System.out.println("flatMap==" + s));
1
2
3
4
5
6
7
8
9
10
11
12
输出如下:

map==java.util.stream.ReferencePipeline&[email protected]
map==java.util.stream.ReferencePipeline&[email protected]
map==java.util.stream.ReferencePipeline&[email protected]
flatMap==aa
flatMap==bb
flatMap==cc
flatMap==dd
flatMap==ee
flatMap==ff
可以看出map就是将数组流直接返回,flatMap是将数组流中的每个元素都返回。flatMapToInt,flatMapToLong,flatMapToDouble类似,只不过返回的是对应的类型的流,此处不做演示。

distinct:将集合中的元素去重。
List<String> disList = Arrays.asList("aaa","ddd","bbb","ddd","aaa");
disList.stream()
.distinct()
.forEach(s-> System.out.println(s));
1
2
3
4
输出如下:

aaa
ddd
bbb
sorted:将集合中的元素排序。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream()
.sorted()
.forEach(s-> System.out.println(s));
1
2
3
4
输出如下:

1
2
3
4
可以按照自定义排序:

integerList.stream()
.sorted((s1,s2)->s2.compareTo(s1))
.forEach(s-> System.out.println(s));
1
2
3
输出如下:

4
3
2
1
peek:生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数即引用的方法A,当Stream每个元素被消费的时候都会先执行新Stream给定的方法A。peek是中间操作,如果pee后没有最终操作,则peek不会执行。
integerList.stream()
.peek(s-> System.out.println("peek = "+s));
1
2
此时没有输出,代码改为:

integerList.stream()
.peek(s-> System.out.println("peek = "+s))
.forEach(s-> System.out.println("forEach = "+s));
1
2
3
输出如下:

peek = 1
forEach = 1
peek = 2
forEach = 2
peek = 3
forEach = 3
peek = 4
forEach = 4
limit:返回Stream的前n个元素。
integerList.stream()
.limit(1)
.forEach(s-> System.out.println(s));
1
2
3
输出为:

1
skip:删除Stream的前n个元素。
integerList.stream()
.skip(1)
.forEach(s-> System.out.println(s));
1
2
3
输出如下:

2
3
4
forEach:遍历Stream中的每个元素,前面每个例子都有使用,此处不再演示。
forEachOrdered:遍历Stream中的每个元素。
区别:
在串行流(stream)中没有区别,在并行流(parallelStream)中如果数据源是有序集合,forEachOrdered输出顺序与数据源中顺序一致,forEach则是乱序。
看下使用forEach:

integerList.stream()
.forEach(s-> System.out.println(s));
1
2
输出(多次测试,每次结果都不一样):

3
1
4
2
再看使用forEachOrdered:

integerList.parallelStream()
.forEachOrdered(s-> System.out.println(s));
1
2
输出(测试多次,每次都是这个结果,与integerList中的元素顺序一致):

2
1
3
4
toArray:将流转换为Object[]或者指定类型的数组。
Object[] array = integerList.stream().toArray();
String[] strArr = integerList.stream().toArray(String[]::new);
1
2
reduce:将集合中的每个元素聚合成一条数据。有三种情况:
reduce(BinaryOperator accumulator):此处需要一个参数,返回Optional对象:
Optional<Integer> reduce = integerList.stream().reduce((a, b) -> a + b);
1
reduce(T identity, BinaryOperator accumulator):此处需要两个参数,第一个参数为起始值,第二个参数为引用的方法。从起始值开始,每个元素执行一次引用的方法(方法引用的中的两个参数:第一个参数为上个元素执行方法引用的结果,第二个参数为当前元素)。
int integer = integerList.stream().reduce(5,(a, b) -> a + b);
System.out.println(integer);
1
2
输出为:

15
此例中使用起始值为5,对集合中每个元素求和,可以理解为:5+2+1+3+4=15。

reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner):此处需要三个参数。此方法用在并发流(parallelStream)中,启动多个子线程使用accumulator进行并行计算,最终使用combiner对子线程结果进行合并,返回identity类型的数据,看到有篇文章对这个解释比较清楚:java8中3个参数的reduce方法怎么理解?
collect:将流转换成集合或聚合元素。有两种情况。接受一个参数和接受三个参数(三个参数在并发流parallelStream中使用),此处介绍一个参数的情况,单个参数接受的参数类型为Collector,Collectors 类实现了很多归约操作,详见:java8之collector
List<Integer> collects = integerList.stream()
.filter(a -> a > 1)
.collect(Collectors.toList());
System.out.println(collects);
1
2
3
4
此处统计集合中大于1的元素并最终返回list。输出如下:

[2, 3, 4]
min:获取集合中最小值。
Integer min = integerList.stream()
.filter(a -> a > 1)
.min((Integer a, Integer b) -> a.compareTo(b))
.get();
System.out.println(min);
1
2
3
4
5
输出为:

2
max:获取集合中最大值。
Integer max = integerList.stream()
.filter(a -> a > 1)
.max((Integer a, Integer b) -> a.compareTo(b))
.get();
System.out.println(max);
1
2
3
4
5
输出为:

4
count:获取集合中元素个数
long count = integerList.stream()
.filter(a -> a > 1)
.count();
System.out.println(count);
1
2
3
4
输出为:

3
anyMatch: Stream 中任意一个元素符合传入的 predicate,返回 true
allMatch:Stream 中全部元素符合传入的 predicate,返回 true
noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
boolean b = integerList.stream()
.anyMatch(s -> s > 0);
boolean b1 = integerList.stream()
.allMatch(s -> s > 0);
boolean b2 = integerList.stream()
.noneMatch(s -> s > 0);
System.out.println("anyMatch = " + b);
System.out.println("allMatch = " + b1);
System.out.println("noneMatch = " + b2);
1
2
3
4
5
6
7
8
9
输出:

anyMatch = true
allMatch = true
noneMatch = false
findFirst:如果数据源是有序集合,返回Stream 中第一个元素的Optional对象,如果是无序集合,则返回Stream 中任意一个元素的Optional对象。
Integer first = integerList.stream()
.findFirst()
.get();
System.out.println(first);
1
2
3
4
输出为:

2
findAny:返回Stream 中任意一个元素的Optional对象。
Integer any = integerList.stream()
.findAny()
.get();
System.out.println(any);
1
2
3
4
输出为:

2
Stream还有几个静态方法,返回都是Stream对象。
静态方法如下:builder(返回Builder对象)、empty、of、iterate、generate、concat。
builder:返回一个Builder对象,Builder对象在调用build()返回Stream对象。
empty:返回一个空的有序的Stream对象。
of:返回包含单个元素的有序的Stream对象。
iterate:返回一个无限元素的有序的Stream对象。需要两个参数,第一个参数为初始值,第二个参数为要引用的方法,然后会通过递归循环调用引用的方法。

Stream.iterate(2,s->s+s)
.limit(10)
.forEach(s-> System.out.println(s));
1
2
3
输出为:

2
4
8
16
32
64
128
256
512
1024
generate:返回一个无限元素的无序的的Stream对象。需要一个参数,参数为引用的方法,然后会通过循环调用引用的方法来生成元素,常用于生成常量Stream和随机元素Stream。
concat:将两个Stream连接成一个Stream。需要两个Stream作为参数,如果两个Stream都是有序的并且无论参数Stream是否是并行Stream,得到的都是有序的Stream。输出元素顺序为先输出第一个Stream的元素,然后输出第二个Stream的元素。当结果Stream关闭时候,两个参数Stream同时关闭。

Stream.concat(integerList.stream(),disList.stream())
.forEach(s-> System.out.println(s));
1
2
输出为:

2
1
3
4
11
aaa
ddd
33
bbb
ddd
aaa
————————————————
版权声明:本文为CSDN博主「昵称2019」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/bluuusea/article/details/79967039

原文地址:https://www.cnblogs.com/zhuawang/p/11580750.html

时间: 2024-10-04 04:50:23

JAVA8新特性--集合流操作Stream的相关文章

Java8 新特性之集合操作Stream

Java8 新特性之集合操作Stream Stream简介 Java 8引入了全新的Stream API.这里的Stream和I/O流不同,它更像具有Iterable的集合类,但行为和集合类又有所不同. stream是对集合对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作,或者大批量数据操作. 为什么要使用Stream 函数式编程带来的好处尤为明显.这种代码更多地表达了业务逻辑的意图,而不是它的实现机制.易读的代码也易于维护.更可靠.更不容易出错. 高端 使用实例: 测试数据:

Java8新特性(1)—— Stream集合运算流入门学习

废话,写在前面 好久没写博客了,懒了,以后自觉写写博客,每周两三篇吧! 简单记录自己的学习经历,算是对自己的一点小小的督促! Java8的新特性很多,比如流处理在工作中看到很多的地方都在用,是时候扔掉笨重的for循环了!节省40%-50%代码量!Come on! 如题 (总结要点) Stream API只能被消费一次,后续重复使用已建立的流会报异常!所以stream流是线程安全的! 比如执行"stream.forEach(System.out::println);stream.forEach(S

Java8新特性第3章(Stream API)

Stream作为Java8的新特性之一,他与Java IO包中的InputStream和OutputStream完全不是一个概念.Java8中的Stream是对集合功能的一种增强,主要用于对集合对象进行各种非常便利高效的聚合和大批量数据的操作.结合Lambda表达式可以极大的提高开发效率和代码可读性. 假设我们需要把一个集合中的所有形状设置成红色,那么我们可以这样写 for (Shape shape : shapes){ shape.setColor(RED) } 如果使用Java8扩展后的集合

Java8 新特性 Stream 无状态中间操作

无状态中间操作 Java8 新特性 Stream 练习实例 中间无状态操作,可以在单个对单个的数据进行处理.比如:filter(过滤)一个元素的时候,也可以判断,比如map(映射)... 过滤 filter 映射 map 扁夹化 flatMap 遍厉 peek 过滤 filter 接收一个谓词断言,boolean Pridicate< T > 根据返回值类型来确定是否过滤这一条属性. // 过滤 filter @Test public void filterTest() { list.stre

Java8 新特性 Stream 短路终端操作

短路终端操作 Java8 新特性 Stream 练习实例 传入一个谓词,返回传为boolean,如果符合条件,则直接结束流. 匹配所有 allMatch 任意匹配 anymMatch 不匹配 noneMatch 查找首个 findFirst 查找任意 findAny 匹配所有 allMatch //匹配所有 allMatch @Test public void allMatchTest() { boolean b = list.stream() //所有的商品价格都大于40 .allMatch(

Java8 新特性 Stream 非短路终端操作

非短路终端操作 Java8 新特性 Stream 练习实例 非短路终端操作,就是所有的元素都遍厉完,直到最后才结束.用来收集成自己想要的数据. 方法有: 遍厉 forEach 归约 reduce 最大值 max 最小值 min 聚合 collect 计数 count 遍厉 forEach //遍厉 forEach @Test public void forEachTest() { list.stream() .forEach(iter -> //以json格式输出 System.out.prin

乐字节-Java8新特性-接口默认方法之Stream流(下)

接上一篇:<Java8新特性之stream>,下面继续接着讲Stream 5.流的中间操作 常见的流的中间操作,归为以下三大类:筛选和切片流操作.元素映射操作.元素排序操作: 操作 描述 筛选和切片 filter(T -> boolean):保留 boolean 为 true 的元素 limit(long n):返回前 n 个元素 skip(long n):去除前 n 个元素 distinct():去除重复元素,这个方法是通过类的 equals 方法来判断两个元素是否相等的 映射 map

Java8 新特性 Steam() 中间有状态操作

中间有状态操作 Java8 新特性 Stream 练习实例 ??中间操作,就是把数据处理成自己想要的类型,并且有状态操作,是在所有的数据基础上进行操作的.比如dictinct(去重),sorted(排序).... 所有的有状态操作: 去重 distinct 跳过 skip 截断 limit 排序 sorted 去重 distinct //找出所有的对象的类型 @Test public void test1() { list.stream() //找出所有的对象的类型 .map(Sku::getS

36套精品Java高级课,架构课,java8新特性,P2P金融项目,程序设计,功能设计,数据库设计,第三方支付,web安全,高并发,高性能,高可用,分布式,集群,电商,缓存,性能调优,设计模式,项目实战,大型分布式电商项目实战视频教程

新年伊始,学习要趁早,点滴记录,学习就是进步! QQ:1225462853 视频课程包含: 36套Java精品高级课架构课包含:java8新特性,P2P金融项目,程序设计,功能设计,数据库设计,架构设计,web安全,高并发,高性能,高可用,高可扩展,分布式,集群,电商,缓存,性能调优,设计模式,项目实战,工作流,程序调优,负载均衡,Solr集群与应用,主从复制,中间件,全文检索,Spring boot,Spring cloud,Dubbo,Elasticsearch,Redis,ActiveMQ