④对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。
集合优化了对象的存储,而流和对象的处理有关。 流是一系列与特定存储机制无关的元素——实际上,流并没有“存储”之说。 利用流,无需迭代集合中的元素,就可以提取和操作它们。...通过放弃对迭代过程的控制,我们把控制权交给并行化机制。我们将在并发编程一章中学习这部分内容。 另一个重要方面,流是懒加载的。这代表着它只在绝对必要时才计算。你可以将流看作“延迟列表”。...我们注意到在构造函数中循环体使用命令式编程(外部迭代)。在以后的例子中,你甚至会看到我们如何消除这一点。这种旧的形式虽不是特别糟糕,但使用流会让人感觉更好。...我们最后使用到的是 FileToWordsRegexp.java,它的问题是需要将整个文件读入行列表中 —— 显然需要存储该列表。而我们真正想要的是创建一个不需要中间存储层的单词流。...因为我们采用的是内部迭代,而不是外部迭代,所以这是可能实现的。 parallel() 看似简单,实则棘手。更多内容将在稍后的 并发编程 章节中学习。
,传统的并发编程往往因为其复杂性十分容易出错,但使用 streams api 则无需担心这个问题 2.2 Stream 是什么 stream 顾名思义,就是“流”,这个名字突出了集合对象流式处理的含义...他生成一个结果或一个 side effect 事实上,真正触发流的遍历操作的就是 terminal 操作的执行 除此以外,如果流的输入是一个无限大的集合,那么还必须具有 short-circuiting 操作,他有两个作用...2.4.2 Streams API 版本 下面,我们使用 Streams API 来优化上面的代码,整个流程就会显得简单了很多: private static List sortStudents...API 版本的代码显然更加简洁和清晰,可读性、可维护性都有了显著提升,并且如果使用并发模式,Streams API 版本还会在性能上得到增强 由此可见,如果熟练掌握了 Streams API,那么在你的开发过程中...后记 本文我们通过一个例子看到了 Streams API 是如何使用的,以及列出了 java8 中 Streams API 包含的所有操作 那么,这些操作具体应该如何使用呢?
通过放弃对迭代过程的控制,我们把控制权交给并行化机制。我们将在并发编程一章中学习这部分内容。 另一个重要方面,流是懒加载的。这代表着它只在绝对必要时才计算。你可以将流看作“延迟列表”。...我们注意到在构造函数中循环体使用命令式编程(外部迭代)。在以后的例子中,你甚至会看到我们如何消除这一点。这种旧的形式虽不是特别糟糕,但使用流会让人感觉更好。...最后使用到的是 FileToWordsRegexp.java,它的问题是需要将整个文件读入行列表中 —— 显然需要存储该列表。而我们真正想要的是创建一个不需要中间存储层的单词流。...Optional.empty Optional.empty Optional.empty Optional.empty OptionalDouble.empty 当流为空的时候你会获得一个 Optional.empty 对象,而不是抛异常...因为我们采用的是内部迭代,而不是外部迭代,所以这是可能实现的。
在Java8中,Collection 接口被扩展,提供了两个获取流的默认方法,如下所示。...“迭代”的方式生成无限流,而generate()方法主要是使用“生成”的方式生成无限流。...我们可以使用下面的代码示例来使用这两个方法生成Stream流。...迭代 Stream intStream = Stream.iterate(0, (x) -> x + 2); intStream.forEach(System.out::println...Stream intStream = Stream.iterate(0, (x) -> x + 2); intStream.limit(10).forEach(System.out::
extends BaseStream> extends AutoCloseable {//....先忽略这些具体的细节} 由这个接口的定义我们得知,BaseStream是一个泛型接口,它有两个类型参数...,我们上一篇的Demo基本上也是使用Stream接口来做的练习。...,并返回对该迭代器的引用(终端操作) Spliterator spliterator(); //line3 获取流的spliterator,并返回其引用(终端操作) boolean isParallel...一个特别需要注意的点是:中间操作不是立即发生的。相反,当在中间操作创建的新流上执行完终端操作后,中间操作指定的操作才会发生。...当然官方早已考虑到这一点了,前面你们看到的IntStream,LongStream,DoubleStream就是官方给我们提供的处理基本类型的流了。此处是不是应该给他们掌声!
使用新接口可以减轻不必要的自动装箱,从而提效率: IntStream intStream = IntStream.range(1, 3); LongStream longStream = LongStream.rangeClosed...由于JDK中没有接口CharStream,因此使用IntStream表示字符流。用到了String类的chars()方法。...由于调用了limit(2),仅将打印前两个元素。...正如方法所说,peek() 方法的目的是见识流中的元素,而不是对其进行转换。peek方法不会启动流中元素的内部迭代。...如果不是所有元素都与Predicate匹配,则allMatch() 方法将返回false。
虽然流中的元素是 Integer 类型,但 Streams 接口没有定义 sum 方法。 Stream API还提供了原始类型流特化,专门支持处理数值流的方法。...这些方法和前面说的 map 方法的工作方式一样,只是它们返回的是一个特化流,而不是 Stream 。 例如,可以像下面这样用 mapToInt 对 menu 中的卡路里求和: ?...这里, mapToInt 会从每道菜中提取热量(用一个 Integer 表示),并返回一个 IntStream(而不是一个 Stream )。...Java 8引入了两个可以用于 IntStream 和 LongStream 的静态方法,帮助生成这种范围range 和 rangeClosed 。...这两个方法都是第一个参数接受起始值,第二个参数接受结束值。但range 是不包含结?值的,而 rangeClosed 则包含结束值。 ?
源 流会使用一个提供数据的源,如集合、数组或输入/输出资源。 请注意,从有序集合生成流时会保留原有的顺序。由列表生成的流,其元素顺序与列表一致。 3....内部迭代 与使用迭代器显式迭代的集合不同,流的迭代操作是在背后进行的。...相反,Streams库使用内部迭代——它帮你把迭代做了,还把得到的流值存在了某个地方,你只要给出 一个函数说要干什么就可以了。...8引入了两个可以用于IntStream和LongStream的静态方法,帮助生成数值的范围:range和rangeClosed。...这两个方法都是第一个参数接受起始值,第二个参数接受结束值。但 range是不包含结束值的,而rangeClosed则包含结束值。
然后,我们用 [IntStream#sum] 计算它的总数: IntStream intNumbers = IntStream.range(0, 3); assertEquals(3, intNumbers.sum...()); 我们可以从Doubles的列表开始执行类似的操作。...通过使用streams,我们可以使用 mapToDouble 将对象流转换为Double stream: List doubleNumbers = Arrays.asList(23.48...: Identity – 等于0–它是还原的起始值 Accumulator function – 接受两个参数,目前为止的结果,以及流的下一个元素 4....以及如何使用reduce作为替代。
你可能已经猜到了,它是IntStream、LongStream和DoubleStream。 IntStreams可以使用IntStream.range()来代替常规的for循环。...一样,但有以下不同:原始stream使用专门的lambda表达式,例如是IntFunction而不是Function,是IntPredicate,而不是Predicate。...,而不是映射到字符串的对象stream: Stream.of(1.0, 2.0, 3.0) .mapToInt(Double::intValue) .mapToObj(i -> "a"...因此,map将尽可能少地被调用,而不是所有的元素映射到stream中。 为什么顺序很重要 下一个示例包括两个中间操作 map和filter和终端操作forEach。....test7(Streams5.java:38) at com.winterbe.java8.Streams5.main(Streams5.java:28) 为了克服这个限制,必须为要执行的每一个终端操作创建一个新的
将对象流映射为数值流 常用方法为mapToInt, mapToDouble, mapToLong,这些方法和map相同,只是它们返回一个特化流,而不是Stream。...可以使用boxed()方法。 Stream boxed = intStream.boxed(); 默认值OptinalInt 由于数值流经常会有默认值,比如默认为0。...数值特化流的终端操作会返回一个OptinalXXX对象而不是数值。...可以使用for循环,也可以直接使用数值流。...java/com/test/java8/streams/NumStreamExample.java 以上出自《Java8 In Action》
顺序操作通过单线程执行,而并行操作则通过多线程执行。可使用并行流进行操作来提高运行效率 parallelStream 是流并行处理程序的代替方法。...以下代码片段使用 map 将集合元素转为大写 (每个元素映射到大写)-> 降序排序 ->迭代输出: Arrays.asList("abc", "","bc","efg","abcd","", "jkl"...数值特化流的终端操作会返回一个 OptinalXXX 对象而不是数值。...(1, 9); 将数值流转回对象流 // 将数值流转回对象流 Stream boxed = intStream.boxed(); 流的扁平化 案例:对给定单词列表 [“Hello”...flatMap 方法的效果是,各个数组并不是分别映射一个流,而是映射成流的内容,所有使用 map(Array::stream)时生成的单个流被合并起来,即扁平化为一个流。
,而不是在每个单独元素上立即执行操作,从而促进并行执行。...这个例子的串行和并行版本的唯一区别是初始时创建流,使用parallelStream()而不是stream() 当启动终端操作时,流管道是按顺序或并行执行的,这取决于它被调用的流的策略模式。...首先创建一个列表,由两个字符串组成:“one”;和“two”。 然后,从该列表中创建一条stream。接下来,通过添加第三个字符串:“three”来修改列表。...8),对于将mapper函数应用于个别元素的顺序,或者对于给定元素执行任何行为参数的顺序,都没有保证 对许多可能会被尝试使用于副作用的计算中,可以替换为无副作用的,更安全更有效的表达,比如使用归约而不是可变的累积器...然而,我们有充分的理由倾向于reduce操作,而不是像上面这样的迭代累计运算。
, 显式的在集合外部进行迭代, 这叫做外部迭代。...它使用了一个「无限队列」来保存需要执行的任务,而线程的数量则是通过构造函数传入, 如果没有向构造函数中传入希望的线程数量,那么当前计算机可用的CPU数量会被设置为线程数量作为默认值。...正如我们上面那个列子的情况分析得知,lambda的执行并不是瞬间完成的,所有使用parallel streams的程序都有可能成为阻塞程序的源头, 并且在执行过程中程序中的其他部分将无法访问这些workers...,可能最好选择一个并发 收集器(比如 groupingByConcurrent()),它可以忽略遇到顺序, 并让所有线程直接收集到一个共享的并发数据结构中(比如 ConcurrentHashMap),而不是让每个线程收集到它自己的中间映射中...什么时候该使用并行流 谈了这么多,关于并行流parallelStream的使用注意事项需要格外注意,它并不是解决性能的万金油,相反,如果使用不当会严重影响性能。我会在另外一篇文章里单独谈这个问题。
当您可以安全地在多个线程上并行执行操作时,操作是原子的,而不使用我以前的教程中所示的synchronized关键字或锁。...迭代在当前线程上顺序执行。..."d3" : value); System.out.println(map.get("r2")); // d3 而不是替换 map 的所有值 compute() 让我们转换单个条目。...在下面的例子中,我们使用一个阈值来总是强制执行并行执行来进行演示。 ForEach 方法forEach()能够并行迭代地图的键值对。...使用当前迭代步骤的键和值调用类型BiConsumer的lambda表达式。为了可视化并行执行,我们将当前线程名称打印到控制台。 请记住,在我的情况下,底层的ForkJoinPool使用三个线程。
Stream是内部迭代 一个明显的区别是迭代方式不同。Collection需要手动for-each或者使用Iterator在外部迭代。...而Stream则开启后可以直接对单个元素进行操作,内部帮你做好了迭代工作。 内部迭代的好处是可一个更好的并行。自己手写迭代需要处理好每次迭代的内容。...统计单词列表中出现的字母。...,使用reduce的好处在于,这里的迭代被内部迭代抽象掉了,这让内部实现得以选择并行执行reduce操作。...而迭代式求和例子要更新共享变量sum,这不是那么容易并行化的。如果你加入了同步,很可能会发现线程竞争抵消了并行本应带来的性能提升!这种计算的并行化需要另一种方法:将输入分块,分块求和,最后再合并起来。
在本文中,您将了解如何使用 IntStream 方法 range、iterate 和 limit 来迭代范围和跳过范围中的值。...在本例中,我们还选择了前递增而不是后递增。 清单 1 中没有太多代码,但比较繁琐。Java 8 提供了一种更简单、更优雅的替代方法:IntStream 的 range 方法。...在清单 8 中,for 循环在迭代期间快速跳过两个值: 清单 8....如果我们决定跳过 3 个值而不是 2 个值,该怎么办?我们不仅需要更改代码,结果也很容易出错。我们需要有一个更好的方法。...逆向迭代 与正向迭代相比,逆向迭代同样非常简单,无论使用传统的 for 循环还是 IntStream。 以下是一个逆向的 for 循环迭代: 清单 11.
的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。...它使用了一个「无限队列」来保存需要执行的任务,而线程的数量则是通过构造函数传入, 如果没有向构造函数中传入希望的线程数量,那么当前计算机可用的 CPU 数量会被设置为线程数量作为默认值。...正如我们上面那个列子的情况分析得知,lambda 的执行并不是瞬间完成的, 所有使用 parallel streams 的程序都有可能成为阻塞程序的源头, 并且在执行过程中程序中的其他部分将无法访问这些...,可能最好选择一个并发 收集器(比如 groupingByConcurrent()),它可以忽略遇到顺序, 并让所有线程直接收集到一个共享的并发数据结构中(比如 ConcurrentHashMap),而不是让每个线程收集到它自己的中间映射中...### 什么时候该使用并行流 谈了这么多,关于并行流parallelStream的使用注意事项需要格外注意,它并不是解决性能的万金油,相反,如果使用不当会严重影响性能。
Stream流编程-概念 概念: 这个Stream并非是I/O流里的Stream,也不是集合元素,更不是数据结构,它是JDK1.8带来的新特性,是一种用函数式编程在集合类上进行复杂操作的工具。...内部迭代与外部迭代: 使用for循环等利用Iterator进行迭代操作的,我们都叫做外部迭代,而使用stream流进行迭代操作的叫做内部迭代。...("计算结果为:" + sum); // 计算结果为:6 使用stream内部迭代示例代码: int[] nums = {1, 2, 3}; // 使用stream进行内部迭代 int sum = IntStream.of...如果返回值不是Stream或者为空,则该操作是终止操作。 如下图所示,前两个操作是中间操作,只有最后一个操作是终止操作: ?...如果现在有一个需求:当进行第一步操作时需使用并行流,而第二步操作则需使用串行流。那么我们可以通过结合这两个方法来实现这个需求吗?
领取专属 10元无门槛券
手把手带您无忧上云