在这章中我们将学习Stream API,在JDK 8 中的一项新的特性。为了理解这一章的主题,你需要知道如何使用Lambda表达式和java.util.function里的预定义的函数式接口。

  一个Stream 类似于一个管道,但它里面运输的不是水和石油,而是把数据从源头运输到目的地。根据传递的方式,一个stream可以是并行和并发的。并行的stream运行在多核的CPU的机器上会很有用。

  乍一看,一个stream就像是一个集合容器,但是,它不是一个数据结构用来存储对象,它只是负责移动对象,所以,你不能把它想象成集合对象那样往它里面添加数据。

  使用stream的主要原因是它支持并行和并发的聚合操作。例如,你可以非常容易地从stream里面过滤,排序或映射元素。

  Stream API的不同的类型在java.util.stream包中。其中Stream接口是这里面最常用的stream类型。 一个Stream可以传递任何类型的对象,同时也有几个特殊化的Stream:IntStream, LongStream and DoubleStream。他们都来源于BaseStream。

  下面的表格展示了一些在Stream接口中常见的方法:

方法   描述
concat  懒加载的方式连接两个stream。返回一个新的stream,他的元素包括两个stream的所有元素。第一个stream的元素后面紧跟着第二个stram的元素。
count  返回stream里面元素的个数。
empty  创建并返回一个空的stream。
filter  在stream所有的元素中根据给定的断言接口返回一个新的stream。
forEach  给stream每个元素执行一个操作。
limit  从当前的stream中根据指定最大元素的个数返回一个新的stream。
map  返回包含了应用于stream的元素的给定的方法的的结果的stream。
max  根据比较器返回stream中最大的元素。
min  根据比较器返回stream中最小的元素。
of  返回一个已经给定了值的stream。
reduce  在stream上使用唯一ID和累加器执行递减操作。
sorted  返回一个新的使用自然排序的stream。
toArray  返回一个包含stream所有元素的数组。

有些stream的方法执行中间过程的操作,有的执行最终的操作。中间过程的操作会把一个stream传输到另一个stream中。像filter,Map,sorted等这些方法。

执行最终操作的方法会产生结果或是其他的影响。例如,count,forEach就是执行的最终结果的操作。

中间过程的操作属于懒加载的方式,他不会真正的执行,只有是执行最终结果的才会真正在源上开始计算。

创建和获取一个Stream

你可以使用Stream中静态的of方法来创建一个连续的stream。例如,下面的例子就是创建了一个包含三个Integer类型元素的stream。

  Stream<Integer> stream = Stream.of(100, 200, 300);

或者,给of方法传递一个数组:

  String[] names = {"Bart", "Lisa", "Maggie"};
  Stream<String> stream = Stream.of(names);

现在java.util.Arrays 帮助类已经有了method方法用来转换一个数组给stream。例如,你可以重写上面的代码,使用Arrays类创建一个stream。

  String[] names = {"Bart", "Lisa", "Maggie"};
  Stream<String> stream = Arrays.stream(names);

另外,在java.util.Collectiond接口中也有个了默认的stream和parallelStream方法分别用来返回一个顺序的stream和并行的stream。签名如下:

  default java.util.stream.Stream<E> stream()
  default java.util.stream.Stream<E> parallelStream()

多亏了Collection接口中的这些方法,从List或Set中获取stream简直小菜一碟。

除此而外,在java.nio.file.Files类中提供了两个返回Stream<Path>的方法:list和walk。list方法返回一个指定路径的入口的泛型为Path的stream。walk方法遍历了给定路径下入口里所有的文件并作为stream返回。

Files 也包含了lines方法返回泛型为String的stream的所有行的文本。

看下面的例子。

import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;public class ObtainStreamDemo {public static void main(String[] args) throws IOException {Path path = Paths.get(".");// use list method.Stream<Path> list = Files.list(path);list.forEach(System.out::println);list.close();System.out.println("===========================================");// use walk method.Stream<Path> walk = Files.walk(path, FileVisitOption.FOLLOW_LINKS);walk.forEach(System.out::println);walk.close();}}

连接两个stream

在Stream接口中提供了concat方法用来以懒加载的方式连接两个stream。这个方法返回一个新的stream,它的元素是两个stream的所有元素,并且第二个stream的元素接在第一个stream元素的后面。

看下面的例子。

import java.util.stream.Stream;public class StreamConcatDemo {public static void main(String[] args) {Stream<String> stream1 = Stream.of("January", "Christie");Stream<String> stream2 = Stream.of("Okanagan", "Sydney", "Alpha");Stream.concat(stream1, stream2).sorted().forEach(System.out::println);}}

需要注意的是,此方法不会剔除重复的元素,如果有相同的元素,都一并连接在一个新的stream中。

过滤。

当你从stream中基于一定的条件过滤该stream并返回一个新的包含选定的元素的stream。你可以在Stream对象上调用filter方法,并传递一个predicate函数式接口,由它来决定哪些元素包含在新的stream中。

filter方法的签名如下:

  Stream<T> filter(java.util.function.Predicate<? super T> predicate)

下面的例子,从exapmle.txt中读取文件,并过滤掉注释行(已“#”开头的)和空白行。

public class StreamFilterDemo1 {public static void main(String[] args) {Predicate<String> notCommentOrEmptyLine= (line) -> line.trim().length() > 0&& !line.trim().startsWith("#");try (FileReader fr = new FileReader("example.txt");BufferedReader br = new BufferedReader(fr)) {Stream<String> lines = br.lines();lines.filter(notCommentOrEmptyLine).forEach(System.out::println);} catch (IOException e) {e.printStackTrace();}}
}

example.txt:

# Set path so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; thenPATH="$HOME/bin:$PATH"fi

执行结果如下:
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

第二个例子是使用stream实现在你机器上的文件搜索。为了精确些,代码只显示在给定的目录和子目录下后缀名为java的文件。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;public class StreamFilterDemo2 {public static void main(String[] args) {// find all java files in the parent directory and// all its subdirectoriesPath parent = Paths.get("..");try {Stream<Path> list = Files.walk(parent);list.filter((Path p) -> p.toString().endsWith(".java")).forEach(System.out::println);} catch (IOException ex) {ex.printStackTrace();}}
}

StreamFilterDemo2 类开始从当前目录的父目录开始执行,它传递了Path给Files.walk方法去获取泛型为Paths的stream,接着根据predicate接口只包含后缀名为.java的文件,并用forEach遍历打印。

Upgrading to Java 8——第四章 The Stream API相关推荐

  1. 尚学堂java实战第四章课后习题

    尚学堂java实战第四章课后习题 文章中的题目答案仅供参考 选择题答案: 1.B 解析:一个java类必然存在构造器,即使没有定义构造器,也会存在一个默认的无参构造器. 2.D 3.AC 解析: A( ...

  2. 疯狂java讲义第四章习题答案

    1.使用循环输出九九乘法表. 疯狂java讲义第四章课后习题第1题答案 2.根据给定的层数,使用循环输出等腰三角形. 疯狂java讲义第四章课后习题第2题答案 3.给定半径输出圆形. 需要注意的是,计 ...

  3. JAVA数据库第四章上机3_Java第二至第四章上机练习题

    Java第二章~第四章上机题 以下页码见第8版教材 1.完成P53页2.14题 2.完成P53页2.15题,请使用循环编程.输入分别为半年,一年. 3.同上题描述进行编程,问要存多少个月,获得的利息大 ...

  4. java第十四章上机四客户类_java语言程序设计教学大纲.doc

    java语言程序设计教学大纲.doc 还剩 5页未读, 继续阅读 下载文档到电脑,马上远离加班熬夜! 亲,喜欢就下载吧,价低环保! 内容要点: 第六章 结构控制 2 2第七章 数组 2第八章 字符串 ...

  5. JAVA基础第四章-集合框架Collection篇

    业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...

  6. java9 反应编程_Java9第四篇-Reactive Stream API响应式编程

    file 我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把ja ...

  7. java基础知识——流式计算Stream API

    文章目录 一.基本概念 二.创建流 三.中间操作 3.1 filter 3.2 map 3.3 distinct 3.4 sorted 3.5 limit 3.6 skip 3.7 flatMap 四 ...

  8. iterate在java中的_Java 9中Stream API的iterate()方法的重要性?

    在Java 8中,Stream API的iterate()方法将种子和一元运算符作为参数.随着流变得无限,它使开发人员可以通过使用limit,findFirst,findAny等添加显式终止条件.在J ...

  9. Java OOP 第四章 抽象类和接口

    Java OOP 抽象类和接口 文章目录 Java OOP 抽象类和接口 一.学习目标 二.抽象类 三.抽象类 (abstract) 四.抽象方法 五.抽象类和抽象方法的应用 六.final用法 七. ...

  10. Java学习 第四章 java面向对象(二)

    一.封装性 1.封装性产生目的 保护某些属性和方法不被外部所看见. 2.封装性的实现  为属性和方法进行封装是通过关键字private声明的;  实现该属性的set和get方法,为外部所访问:  eg ...

最新文章

  1. VS2010 SP1 Beta与VisualSVN的冲突引起VS2010关闭时重启
  2. jQuery代码优化的9种方法
  3. 一次非常有意思的sql优化经历
  4. Linux与Windows数据传输
  5. OpenGL:纹理Textures
  6. jdbc:log4jdbc_使用Log4jdbc记录JDBC操作
  7. WinAPI: PolylineTo - 绘制一组连续线段(更新当前位置)
  8. 计算机可以待机无法关机,win7怎么设置不待机?如何设置自动关机的方法【详解】...
  9. vshost32.exe停止工作
  10. js实现前端根据部对象属性对对象数组进行排序
  11. Mxnet框架学习笔记(一):常用数据操作方法学习记录
  12. USB转RS485/RS422接线说明
  13. mes系统服务器架构,MES系统三大层结构是什么
  14. Selenium-WEB自动化学习笔记--更新ing
  15. 湖南大学计算机专业推免生,湖南大学2018年招收推荐免试攻读研究生简章
  16. C语言编写取单词首字母,C语言练习之单词首字母大写
  17. Flutter地图系列(七)—— 高德地图记录运动轨迹
  18. 前程无忧助力,再次举办湖北武汉网络专场招聘会
  19. 官方公布中国自行车排名十强辐轮王土拨鼠全世界碳纤维自行车品牌
  20. 基于STM32的指纹识别智能锁设计

热门文章

  1. 从零基础入门Tensorflow2.0 ----二、4.1 wide deep 模型(函数式API)
  2. word中设置论文中英文参考文献对齐方法
  3. 单片机c语言跑马灯实验报告,单片机跑马灯实验报告
  4. java 雪崩效应,Jmeter模拟雪崩效应
  5. Flink Batch SQL 1.10 实践
  6. 非科班普通本科就注定进不了大厂?我不服
  7. 听说大家想补补算法和数据结构,给大家推荐一个GitHub 15k星的图文版开源项目...
  8. mysql存储过程详细教程6_存储过程详解(示例代码)
  9. python web改为java_Python是否可以成为Web应用程序的良好替代方案,否则将在Java EE中完成?...
  10. python函数后面的点_对python函数后面有多个括号的理解?