Upgrading to Java 8——第四章 The Stream API
在这章中我们将学习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" ] ; then
PATH="$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 subdirectories
Path 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的更多相关文章
- “全栈2019”Java多线程第四章:设置和获取线程名称
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java异常第四章:catch代码块作用域详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- “全栈2019”Java第九十四章:局部内部类详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第十四章:二进制、八进制、十六进制
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第二十四章:流程控制语句中决策语句switch下篇
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- JAVA基础第四章-集合框架Collection篇
业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...
- 恕我直言你可能真的不会java第12篇-如何使用Stream API对Map类型元素排序
在这篇文章中,您将学习如何使用Java对Map进行排序.前几日有位朋友面试遇到了这个问题,看似很简单的问题,但是如果不仔细研究一下也是很容易让人懵圈的面试题.所以我决定写这样一篇文章.在Java中,有 ...
- Java9第四篇-Reactive Stream API响应式编程
我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 ...
- Java 8新特性(Lambda,Stream API)
由于最近总监要求学习Java 8的一些知识,就去网上找了 一套教程来学习学习,将学习结果做一个小的总结记录,方便以后使用: 1.Java 8的优点 2.Lambda表达式优点 2.1Lambda实例 ...
随机推荐
- 第 2章 数组和 ArrayLists
数组是最通用的数据结构,它出现在几乎所有的编程语言里.在 C#语言中使用数组包括创建 System.Array 类型的数组对象,以及创建针对所有数组的抽象的基类型.Array 类提供了一套方法,这些方 ...
- Windows 和 Linux 下 禁止ping的方法
Windows 和Linux 下 禁止ping的方法 目的: 禁止网络上的其他主机或服务器ping自己的服务器 运行环境: Windows 03.08 linux 方法: Windows 03下: ...
- ASP.NET的学习之asp.net整体运行机制
1.浏览器向服务器发送请求报文,服务器端的软件比如是IIS,接受请求 2.IIS通过aspnet_isapi.dll 这个程序集来请求FrameWork中的ASP.Net框架,这是对于集成模式 3.进 ...
- BF算法和KMP算法(javascript版本)
var str="abcbababcbababcbababcabcbaba";//主串 var ts="bcabcbaba";//子串 function BF( ...
- js问题集锦
1.不在服务器中的访问,如file:///C:/Users/yx/Desktop/index.html这样的地址,ajax是无法访问的,不会执行send();必须放到服务器才可以. 2.阻止正常提交v ...
- 用Python的smtp模块发邮件的示例
# -*- coding: UTF-8 -*- import smtplib from email.mime.multipart import MIMEMultipart from email.mim ...
- 使用了Theme但是没有效果问题
最近在开发过程中使用了theme移植Preference并使用了一些android样式,但是在自定义的Theme修改了相关参数后却无法实现 可能有些朋友还不知道怎么用.这里也做个简要的使用方式说明. ...
- 访问svc 文件,编译器错误消息: CS0016,未能写入输出文件
编译错误 说明: 在编译向该请求提供服务所需资源的过程中出现错误.请检查下列特定错误详细信息并适当地修改源代码. 编译器错误消息: CS0016: 未 ...
- 第六节:宿主如何使用AppDomain
前面已经讨论了宿主以及宿主加载CLR的方式.同时还讨论了宿主如何告诉CLR创建和卸载AppDomain.为了使这些讨论更加具体,下面将描述一些常见的宿主和AppDomain使用情形.特别地,我要解释不 ...
- C 基于UDP实现一个简易的聊天室
引言 本文是围绕Linux udp api 构建一个简易的多人聊天室.重点看思路,帮助我们加深 对udp开发中一些api了解.相对而言udp socket开发相比tcp socket开发注意的细节要少 ...