重走Java基础之Streams(一)

作者:知秋
来源:重走Java基础之Streams(一)


因为经常逛stackoverflow,最近也在看reactive和storm以及前一阵子也用流式ORM框架speedmentSpringboot整合改造了migo2.0中的单点登录,深深的感受到java8已经融入我们很深了,尤其是Spring5对其进行大力支持,觉得有必要再对自己的知识整理一下,顺带就把stackoverflow一些东西自己拿过来整理翻译一下,里面也会加入一些自己的理解

Introduction

流表示一系列元素并支持不同类型的操作来对这些元素执行计算。在Java 8中,Collection接口有两种方法来生成Stream

  • 1)stream()和
  • 2) parallelStream()

流操作包括中间或终端。 中间操作返回一个流,所以我们可以链接多个中间操作而不使用分号。 终端操作是void的或返回非流结果。

Examples

Using Streams

A Stream是可以执行顺序和并行聚合操作的一系列元素 。 任何给定的“Stream”都可能有无限量的数据流过它。 你所得到的结果是从“Stream”接收的数据在到达时被单独处理,而不是完全对数据执行批处理。 当与lambda表达式 结合时,它们提供了使用函数方法对数据序列执行操作的简明方法。

Example: (see it work on Ideone)

Stream<String> fruitStream = Stream.of("apple", "banana", "pear", "kiwi", "orange");

fruitStream.filter(s -> s.contains("a"))
           .map(String::toUpperCase)
           .sorted()
           .forEach(System.out::println);

Output:

APPLE
BANANA
ORANGE
PEAR

上述代码执行的操作可以总结如下:

  1. 使用静态工厂方法Stream.of(values)创建一个包含fruit String的顺序排序StreamStream 元素

  2. filter()操作仅保留与给定谓词(由谓词返回true测试时的元素)匹配的元素。 在这种情况下,它保留含有“a”的元素。 谓词作为lambda表达式给出。

  3. map() 操作转换 每个元素使用给定的函数,称为映射器。 在这种情况下,每个fruit String使用method-reference映射到将string字符串转换为大写版本String::toUppercase

    Note 如果映射函数返回与其输入参数不同的类型,那么map()操作将返回具有不同泛型类型的流。 例如在一个Stream调用.map(String :: isEmpty)返回一个Stream<Boolean>

  4. sorted()操作对Stream的元素进行排序 根据它们的自然排序(根据在'String'的情况下对所在字典的顺序,其实都知道)。

  5. 最后, forEach(action) 操作执行一个动作,作用于“Stream”的每个元素,将其传递给一个 Consumer。 在该示例中,每个元素只是被打印到控制台。 该操作是终端操作,因此不可能再次进行操作。

  6. NoteStream中定义的操作之所以被执行,是因为最后有终端操作。 假如没有终端操作,'Stream'将不被处理,因为'Stream'输出不被任何终端操作使用(省的浪费计算资源,所以很多书上称之为被动式foreach)。

Chained operations

操作(如上所示)链接在一起以形成可以被视为对数据的查询


Reusing Streams

一个Stream不能重复使用。 一旦调用任何中间或终端操作,“Stream”对象将变得不可用。 Stream代替地使用中间Stream对象以便将中间操作链接在一起通过一系列Stream操作来生成一个Stream对象作为中间对象,最后再调用这个生成的Stream对象来完成最终的操作,最后一步的操作只能进行一次,之后,此流已经没了(生命周期已结束)。

Example:

Stream<String> stream =
    Stream.of("d2", "a2", "b1", "b3", "c")
        .filter(s -> s.startsWith("a"));

stream.anyMatch(s -> true);  // The Stream has been used and is now consumed.
stream.noneMatch(s -> true); // IllegalStateException; stream was already used

Closing Streams

Stream接口扩展了 AutoCloseable。Streams可以通过调用 close方法或使用try-with -resource语句来关闭。

请注意,Stream通常不必关闭。仅需要关闭在IO通道上运行的流。 大多数Stream 型不对资源操作,因此不需要关闭。

Stream 应该关闭的示例用例是,当您从文件创建一个Stream 行时:

try(final Stream<String> lines = Files.lines(Paths.get("somePath"))){
    lines.forEach(System.out::println);
}

Stream接口也声明了Stream.onClose() 方法,它允许你注册 Runnable处理程序,当 流关闭。 一个示例用例是产生流的代码需要知道它何时被消耗以执行一些清理。

public Stream<String>streamAndDelete(Path path) throws IOException {
    return Files.lines(path)
        .onClose(()->someClass.deletePath(path));
}

运行处理程序只有在调用close() 方法时才会执行,例如通过try-with-resources:

Path myPath = Paths.get("somePath");

try(final Stream<String> lines = streamAndDelete(myPath)){
    lines.forEach(System.out::println);
}
Files.exists(myPath); // returns false

If close() isn't called, explicitly or implicitly, then the handler will not be called either:
如果没有明确或隐式地调用close(),那么处理程序不会被调用:

streamAndDelete(myPath)
    .forEach(System.out::println);
Files.exists(myPath); // returns true 

Processing Order

Stream对象的处理可以是顺序或 parallel(并行)

在** sequential **模式中,按照“Stream”的源的顺序处理元素。 如果Stream是有序的(例如 SortedMap实现或List,处理过程保证匹配源的排序。 然而,在其他情况下,应注意不要依赖于顺序(参见:是Java的HashMap`` keySet()迭代顺序一致?)。

Example:

List<Integer> integerList = Arrays.asList(0, 1, 2, 3, 42); 

// sequential 
long howManyOddNumbers = integerList.stream()
                                    .filter(e -> (e % 2) == 1).count(); 

System.out.println(howManyOddNumbers); // Output: 2

Live on Ideone

并行模式允许在多个核上使用多个线程,但不能保证处理元素的顺序。

如果在顺序的 Stream 上虽然调用了多个方法,则不一定必须要调用每个方法。 例如,如果一个 Stream 被过滤,并且元素的数量减少到一,则不会发生对诸如sort的方法的后续调用。 这可以提高顺序的Stream的性能 - 这是一个并行的Stream不可能实现的优化。

Example:

// parallel
long howManyOddNumbersParallel = integerList.parallelStream()
                                            .filter(e -> (e % 2) == 1).count();
System.out.println(howManyOddNumbersParallel); // Output: 2

Live on Ideone


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 来源:重走Java基础之Streams(四)作者:知秋博客:一叶知秋转载请注明来源和作者! 接上篇重走Java基础...
    极乐君阅读 475评论 0 3
  • 来源:重走Java基础之Streams(二)作者:知秋(极乐科技知乎专栏原创作者)博客:一叶知秋 接上篇重走Jav...
    极乐君阅读 506评论 0 2
  • 本文采用实例驱动的方式,对JAVA8的stream API进行一个深入的介绍。虽然JAVA8中的stream AP...
    浮梁翁阅读 25,729评论 3 50
  • 第一章 为什么要关心Java 8 使用Stream库来选择最佳低级执行机制可以避免使用Synchronized(同...
    谢随安阅读 1,486评论 0 4