没有合适的资源?快使用搜索试试~ 我知道了~
首页Java Stream 使用详解
Stream是 Java 8新增加的类,用来补充集合类。 Stream代表数据流,流中的数据元素的数量可能是有限的,也可能是无限的。 Stream和其它集合类的区别在于:其它集合类主要关注与有限数量的数据的访问和有效管理(增删改),而Stream并没有提供访问和管理元素的方式,而是通过声明数据源的方式,利用可计算的操作在数据源上执行,当然BaseStream.iterator()和BaseStream.spliterator()操作提供了遍历元素的方法。 Java Stream提供了提供了串行和并行两种类型的流,保持一致的接口,提供函数式编程方式,以管道方式提供中间操作和终执
资源详情
资源评论
资源推荐

Java Stream 使用详解使用详解
Stream是 Java 8新增加的类,用来补充集合类。
Stream代表数据流,流中的数据元素的数量可能是有限的,也可能是无限的。
Stream和其它集合类的区别在于:其它集合类主要关注与有限数量的数据的访问和有效管理(增删改),而Stream并没有
提供访问和管理元素的方式,而是通过声明数据源的方式,利用可计算的操作在数据源上执行,当然BaseStream.iterator()和
BaseStream.spliterator()操作提供了遍历元素的方法。
Java Stream提供了提供了串行和并行两种类型的流,保持一致的接口,提供函数式编程方式,以管道方式提供中间操作
和终执行操作,为Java语言的集合提供了现代语言提供的类似的高阶函数操作,简化和提高了Java集合的功能。
本文首先介绍Java Stream的特点,然后按照功能分类逐个介绍流的中间操作和终点操作,后会介绍第三方为Java
Stream做的扩展。
前年年底的时候我写了一些关于Java 8 Lambda和Stream的文章,本文应该在那个时候完成。后来忙于项目和写《Scala
集合技术手册》(Scala Collections Cookbook)这本书,一直没来得及写Java Stream的文章,现在这篇文章算是对 Java
Stream的一个总结吧。
介绍
本节翻译整理自 Javadoc ,并对流的这些特性做了进一步的解释。
Stream接口还包含几个基本类型的子接口如IntStream, LongStream 和 DoubleStream。
关于流和其它集合具体的区别,可以参照下面的列表:
不存储数据 。流是基于数据源的对象,它本身不存储数据元素,而是通过管道将数据源的元素传递给操作。
函数式编程 。流的操作不会修改数据源,例如filter不会将数据源中的数据删除。
延迟操作 。流的很多操作如filter,map等中间操作是延迟执行的,只有到终点操作才会将操作顺序执行。
可以解绑 。对于无限数量的流,有些操作是可以在有限的时间完成的,比如limit(n)或findFirst(),这些操作可是实现”短
路”(Short-circuiting),访问到有限的元素后可以返回。
纯消费 。流的元素只能访问一次,类似Iterator,操作没有回头路,如果你想从头重新访问流的元素,对不起,你得重新
生成一个新的流。
流的操作是以管道的方式串起来的。流管道包含一个数据源,接着包含零到N个中间操作,后以一个终点操作结束。
并行 Parallelism
所有的流操作都可以串行执行或者并行执行。除非显示地创建并行流,否则Java库中创建的都是串行流。
Collection.stream()为集合创建串行流而Collection.parallelStream()为集合创建并行流。IntStream.range(int, int)创建的是串
行流。通过parallel()方法可以将串行流转换成并行流,sequential()方法将流转换成并行流。
除非方法的Javadoc中指明了方法在并行执行的时候结果是不确定(比如findAny、forEach),否则串行和并行执行的结果
应该是一样的。
不干涉 Non-interference
流可以从非线程安全的集合中创建,当流的管道执行的时候,非concurrent数据源不应该被改变。下面的代码会抛出
java.util.ConcurrentModificationException异常:
List<String> l = new ArrayList(Arrays.asList("one", "two"));Stream<String> sl = l.stream();sl.forEach(s ->
l.add("three"));
在设置中间操作的时候,可以更改数据源,只有在执行终点操作的时候,才有可能出现并发问题(抛出异常,或者不期望
的结果),比如下面的代码不会抛出异常:
List<String> l = new ArrayList(Arrays.asList("one", "two"));Stream<String> sl =
l.stream();l.add("three");sl.forEach(System.out::println);
对于concurrent数据源,不会有这样的问题,比如下面的代码很正常:
List<String> l = new CopyOnWriteArrayList<>(Arrays.asList("one", "two"));Stream<String> sl = l.stream();sl.forEach(s
-> l.add("three"));
虽然我们上面例子是在终点操作中对非并发数据源进行修改,但是非并发数据源也可能在其它线程中修改,同样会有并发
问题。
无状态 Stateless behaviors
大部分流的操作的参数都是函数式接口,可以使用Lambda表达式实现。它们用来描述用户的行为,称之为行为参数
(behavioral parameters)。
如果这些行为参数有状态,则流的操作的结果可能是不确定的,比如下面的代码:
List<String> l = new ArrayList(Arrays.asList("one", "two", ……));class State { boolean s;}final State state = new
State();Stream<String> sl = l.stream().map(e -> { if (state.s) return "OK"; else { state.s = true; return e; }
});sl.forEach(System.out::println);
上面的代码在并行执行时多次的执行结果可能是不同的。这是因为这个lambda表达式是有状态的。
副作用 Side-effects
有副作用的行为参数是被鼓励使用的。
副作用指的是行为参数在执行的时候有输入输入,比如网络输入输出等。
这是因为Java不保证这些副作用对其它线程可见,也不保证相同流管道上的同样的元素的不同的操作运行在同一个线程
中。
很多有副作用的行为参数可以被转换成无副作用的实现。一般来说println()这样的副作用代码不会有害。
ArrayList<String> results = new ArrayList<>();stream.filter(s -> pattern.matcher(s).matches()) .forEach(s ->
results.add(s)); // 副作用代码
上面的代码可以改成无副作用的。
List<String>results = stream.filter(s -> pattern.matcher(s).matches()) .collect(Collectors.toList()); // No side-
effects!
排序 Ordering
某些流的返回的元素是有确定顺序的,我们称之为encounter order。这个顺序是流提供它的元素的顺序,比如数组的













weixin_38556985
- 粉丝: 3
- 资源: 906
上传资源 快速赚钱
我的内容管理 收起
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助

会员权益专享
安全验证
文档复制为VIP权益,开通VIP直接复制

评论0