目录
parallelStream的实现:ForkJoinPool
流是什么
Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream。Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。
上面是官方的解释,我认为流是一种处理数据的思路,或者说是一种更好的方法,以前我们总是把数据一个一个遍历元素并对其执行某些操作, 使用流就是我先定义要进行什么操作,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
那不是还要进行遍历吗?没有节省开支啊.
首先我们节省了代码量,使用了更优雅的代码; 其次对于空间复杂度,如果入参是流的形式,就可以大大的节省内存占用,意思就是我们之前的数据是全部放入内存中再进行处理,非常巨大的集合类会占用大量的内存,而现在可以来一个数据就用我定义好的处理方式处理一个,因为Stream的元素是在访问的时候才被计算出来(延迟计算),而不用占用大量的内存.而且对于时间复杂度,Stream 依赖于 Java7 中引入的 Fork/Join 框架可以实现并行, 来拆分任务和加速处理过程。
- 对于大量数据可以不存入内存, 流式的处理
- 更简洁的代码
- 可以很方便的并行处理
总结一下,对集合进行代码简洁,清晰但不一定易读(可读性其实不高,而且不方便debug,不抛出checked异常),不一定高效(效率其实有时不如for循环) 的转换、过滤、聚合等操作,“高级版”的迭代器,而和迭代器又不同的是,Stream可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出(但并发功能慎用,对于IO密集型操作,都使用默认的线程池会导致其他任务被阻塞)
stream的意义是更优雅(简洁)的实现一些数据操作(主要是迭代),但效率不一定比传统写法高.因为其简洁性,不应该在其中写入太多代码.
生成流
当我们使用一个流的时候,通常包括三个基本步骤:
获取一个数据源(source)→ 数据转换→执行操作获取想要的结果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道.
流的操作类型分为两种:
- Intermediate(中间操作):一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
- Terminal(终端操作):一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
流是一个懒加载的模式 未结束流前不会进行操作,只要结束流以后才会操作返回结果.
Stream操作分类 |
||
中间操作(Intermediate operations) |
无状态(Stateless) |
map() mapToInt() mapToLong() mapToDouble() flatMap() flatMapToInt() flatMapToLong() flatMapToDouble() filter() peek() unordered() |
有状态(Stateful) |
distinct() sorted() limit() skip() |
|
终端操作(Terminal operations) |
非短路操作 |
forEach() forEachOrdered() toArray() reduce() collect() max() min() count() |
短路操作(short-circuiting) |
anyMatch() allMatch() noneMatch() findFirst() findAny() |
1. 直接对collection.stream()
List<String> list = Arrays.asList("1","2","3","4");
Stream<String> stream1 = list.stream();
2.对于数组
String[] s = new String[]{"1","2","3","4"};
Stream<String> stream2 = Arrays.stream(s);
3.直接构建一个流
Stream<String> stream3 = Stream.of("1","2","3","4");
4.读取文件流