热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java8Stream介绍

Java8Stream介绍1简介Java8新增了java.util.stream.Stream类,它与java.io包里的InputStream和OutputStream中的流是完

=Java8 Stream介绍=
1 简介
Java8新增了java.util.stream.Stream类,它与java.io包里的InputStream和OutputStream中的流是完全不同的概念。Stream是对集合(Collection)对象功能的增强,它专注于对集合对象进行聚合操作或者大批量数据操作。Stream API借助于同时出现的Lambda表达式,极大地提高编程效率和程序可读性。同时它提供串行和并行两种模式进行聚合操作,并行模式能够充分利用多核处理器的优势,使用Java7开始提供的fork/join并行执行框架来拆分和加速处理过程。java.util.stream是一个函数式语言+多核时代综合影响的产物。
Java的集合API中,仅有极少量的辅助型聚合操作方法,更多的时候需要遍历集合来完成相关的聚合逻辑,这种外部迭代远不够高效。这也是Stream产生的原因之一。
2 流的构成
当我们使用一个流的时候,通常包括三个基本步骤:创建流->中间操作*(Intermediate)->终止操作(Terminal)。
示例:
List list = new ArrayList<>();
long count = list.stream().filter(w -> w.length() > 1).count();
创建流://list.stream()//
中间操作://.filter(w -> w.length() > 1)//
终止操作://.count()//
(NOTE)在使用Stream时,经常会遇到一些带@FunctionalInterface注解的接口,这些称为函数式接口。函数式接口的特点是:里面只能有一个抽象方法。它的用途主要在Lambda表达式和方法引用上。关于FunctionalInterface可参考[[https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html | Java doc]]和[[https://www.cnblogs.com/runningTurtle/p/7092632.html | 这篇博客]]还有[[https://blog.csdn.net/qq_38983577/article/details/81806012 | 这篇]]。

=2.1 创建流的方式=
以下列举一些常见的创建流的方式:
(1) 通过集合创建
任何实现Collection接口的类都可以通过这两个方法来创建流:
default Stream stream(); // 串行流
default Stream parallelStream(); // 并行流
(2) 通过Stream.of()
static Stream of(T… values); // 返回其元素是指定值的顺序排序流
static Stream of(T t); // 返回包含单个元素的顺序Stream
(NOTE)&#8221;…&#8221;表示可变长参数,就是这个位置可以传入任意个该类型的参数或一个该类型数组

例:
Stream stream = Stream.of(“a”, “b”, “c”);
Stream stream2 = Stream.of(new String[]{“a”, “b”, “c”});
(3) 通过Arrsys.stream()
static Stream stream(T[] array);
Arrays.stream()有很多重载方法,可以按需使用。
(4) 通过Stream.Builder创建
相关方法:
static Stream.Builder builder(); // 返回一个Stream的构造器
default Stream.Builder add(T t); // 向要构建的流添加元素
Stream build(); // 构建流,将构建器转换为内置状态
例:
Stream stream = Stream.builder()
.add(“a”)
.add(“b”)
.add(“c”)
.build();
(5) 通过generate()和iterate()创建无限流
无限流通常要跟limit()一起使用,限制流中元素的个数。
// 生成
static Stream generate(Supplier s); // 返回无限顺序无序流,其中每个元素由Supplier.get()提供
//迭代
static Stream iterate(T seed, UnaryOperator f); // 返回有序无限连续Stream,其中每个元素由f迭代产生
Supplier和UnaryOperator都是函数式接口。
例①:
Stream stream = Stream.generate(new Supplier() {
long a = 0, b = 1;
@Override
public Long get() {
long temp = a + b;
a = b;
b = temp;
return a;
}
});
stream.limit(10).forEach(System.out::println);
例②:
Stream stream = Stream.iterate(1, n -> n * 2);
stream.limit(11).forEach(System.out::println);
(6) 从文件创建
Files类中提供了一些用于创建Stream的静态方法:
static Stream lines(Path path); // 从文件中读取所有行作为Stream
static Stream walk(Path start, int maxDepth, FileVisitOption… options); // 返回一个Stream,它由给定的起始根文件遍历文件树的路径构成
// 其它的请查看jdk1.8api文档
例:
try (Stream stream = Files.lines(Paths.get(FILE_PATH), StanderdCharsets.UTF_8)) {
stream.forEach(System.out::println);
} catch (IOException e) {}
(NOTE)&#8221;::&#8221;,双冒号运算符,表示方法引用,格式是&#8221;类名::方法名&#8221;,把方法当作参数传到Stream内部,使得Stream里的每个元素都传入到该方法内部执行一下。方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。这个知识点参考[[ https://www.cnblogs.com/xiaoxi/p/7099667.html | Java8之方法引用]]。

(NOTE)Java7中引进了很多新的nio类来取代原来的基于java.io.File的文件IO操作方式,比如这里的Files和Path。Files是一个强大的工具类,提供了一些操作文件的工具方法。Path接口性能更高,在很多场景下可以替换File类。

2.2 中间操作

  • 筛选
    (1) filter
    Stream filter(Predicate predicate);
    predicate是一个函数式接口,表示一个带参数的谓词(给定一个参数,返回boolean类型结果);filter返回由与此给定谓词匹配的此流的元素组成的流,即筛选出符合条件的元素组成新的流。
    例:
    Stream stream = Stream.of(1, 2, 3, 4).filter(i -> i <= 3); // 1, 2, 3
    (2) limit
    Stream limit(long maxSize);
    返回由此流的元素组成的流,截断长度不能超过maxSize。
    例:
    Stream stream = Stream.of(1, 2, 3, 4).limit(2L); // 1, 2
    (3) skip
    Stream skip(long n);
    返回一个抛弃了前n个元素的流,若流中元素不满n个,则返回一个空流。
    例:
    Stream stream = Stream.of(1, 2, 3, 4).skip(2L); // 3, 4
    (4) distinct
    Stream distinct();
    去重,通过流中元素的hashCode()和equals()去除重复元素。自定义的实体使用distinct去重时要重写这两个方法。
    例:
    Stream stream = Stream.of(1, 1, 2, 3).distinct(); // 1, 2, 3

  • 映射
    (5) map
    Stream map(Function mapper);
    返回由给定函数应用于此流的元素的结果组成的流。
    这个方法有三个对于原始类型的变种方法,分别是://mapToInt//,//mapToLong//和//mapToDouble//。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。之所以会有这样三个变种方法,可以免除自动装箱/拆箱的额外消耗。
    例:
    Stream stream = Stream.of(1, 2, 3, 4).map(i -> i * 2); // 2, 4, 6, 8
    (6) flatMap
    Stream flatMap(Function> mapper);
    返回一个通过将提供的映射函数应用于每个元素而产生的映射流的内容来替换该流的每个元素的结果的流。
    由方法签名也可以看出,flatMap接受的映射函数返回值为Stream类型,即每个元素转换得到的是Stream对象,再把子Stream中的元素压缩到父Stream中,是一种扁平化(flat)处理,通常用来处理二维集合。
    map和flatMap的区别:map是一维中的映射;flatMap则是将二维的集合映射成一个一维集合(降维),比map的维度深了一层。
    同样地,flatMap方法也有//flatMapToInt//,//flatMapToLong//和//flatMapToDouble//三个重载方法。
    例:
    Stream stream = Stream.of(new Integer[]{1, 2}, new Integer[]{3, 4}).flatMap(Arrays::stream); // 1, 2, 3, 4
    Stream stream2 = Stream.of(new Integer[]{1, 2}, new Integer[]{3, 4}).map(Arrays::stream); // 使用map,流中元素仍为流
    (NOTE)Tips: ①Function接口原型:Interface Function, T &#8211; 函数的输入类型, R &#8211; 函数的结果类型。②? super: 下界通配符, ? extends: 上界通配符。

  • 排序
    (7) sorted
    Stream sroted(); // 根据自然顺序排序
    Stream sorted(Comparator comparator); // 根据提供的Comparator进行排序
    例:
    Stream stream = Stream.of(1, 2, 4, 3).sorted(); // 1, 2, 3, 4
    Stream stream2 = Stream.of(1, 2, 4, 3).sorted((x, y) -> (x > y) ? -1 : ((x.equals(y)) ? 0 : 1)); // 4, 3, 2, 1
    2.3 终止操作
    (1) 匹配
    boolean allMatch(Predicate predicate); // 返回此流的所有元素是否与提供的谓词匹配
    boolean anyMatch(Predicate predicate); // 返回此流的任何元素是否与提供的谓词匹配
    boolean noneMatch(Predicate predicate); // 返回此流的元素是否与提供的谓词匹配,即!allMatch
    (2) 查找
    Optional findFirst(); // 返回流中第一个元素
    Optional findAny(); // 返回流中任意一个元素,对串行流来说findAny()和findFirst()返回的结果是一样的;对并行流来说不一样,findAny()性能更好。
    查找方法没有参数,可以在查找前用filter加条件。
    (3) 计数
    long count(); // 返回流中元素总数
    (4) 极值
    Optional max(Comparator comparator); // 返回流中最大值
    Optional min(Comparator comparator); // 返回流中最小值
    max和min是要带参数的,例如stream.max(Integer::compareTo)。
    (5) 遍历
    void forEach(Consumer action); // 遍历流中元素,内部迭代
    (6) 规约
    Optional reduce(BinaryOperator accumulator); // 将流中元素迭代地累加起来,返回Optional
    T reduce(T identity, BinaryOperator accumulator); // 提供一个初值,将流中元素迭代地累加起来,返回T类型
    U reduce(U identity, BiFunction accumulator, BinaryOperator combiner); // 提供一个初值,累加方法(二元函数)和结合方法(二元操作符),返回执行结果。
    (7) 收集
    R collect(Collector collector);
    R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner);
    将流转换为其它形式,例如收集到List、Set、Map中。


推荐阅读
  • Node.js 教程第五讲:深入解析 EventEmitter(事件监听与发射机制)
    本文将深入探讨 Node.js 中的 EventEmitter 模块,详细介绍其在事件监听与发射机制中的应用。内容涵盖事件驱动的基本概念、如何在 Node.js 中注册和触发自定义事件,以及 EventEmitter 的核心 API 和使用方法。通过本教程,读者将能够全面理解并熟练运用 EventEmitter 进行高效的事件处理。 ... [详细]
  • HBase Java API 进阶:过滤器详解与应用实例
    本文详细探讨了HBase 1.2.6版本中Java API的高级应用,重点介绍了过滤器的使用方法和实际案例。首先,文章对几种常见的HBase过滤器进行了概述,包括列前缀过滤器(ColumnPrefixFilter)和时间戳过滤器(TimestampsFilter)。此外,还详细讲解了分页过滤器(PageFilter)的实现原理及其在大数据查询中的应用场景。通过具体的代码示例,读者可以更好地理解和掌握这些过滤器的使用技巧,从而提高数据处理的效率和灵活性。 ... [详细]
  • 设计实战 | 10个Kotlin项目深度解析:首页模块开发详解
    设计实战 | 10个Kotlin项目深度解析:首页模块开发详解 ... [详细]
  • 在Python多进程编程中,`multiprocessing`模块是不可或缺的工具。本文详细探讨了该模块在多进程管理中的核心原理,并通过实际代码示例进行了深入分析。文章不仅总结了常见的多进程编程技巧,还提供了解决常见问题的实用方法,帮助读者更好地理解和应用多进程编程技术。 ... [详细]
  • 深入解析 Vue 中的 Axios 请求库
    本文深入探讨了 Vue 中的 Axios 请求库,详细解析了其核心功能与使用方法。Axios 是一个基于 Promise 的 HTTP 客户端,支持浏览器和 Node.js 环境。文章首先介绍了 Axios 的基本概念,随后通过具体示例展示了如何在 Vue 项目中集成和使用 Axios 进行数据请求。无论你是初学者还是有经验的开发者,本文都能为你解决 Vue.js 相关问题提供有价值的参考。 ... [详细]
  • 如何使用和示例代码解析 org.semanticweb.owlapi.model.OWLSubPropertyChainOfAxiom.getPropertyChain() 方法 ... [详细]
  • 在探讨C语言编程文本编辑器的最佳选择与专业推荐时,本文将引导读者构建一个基础的文本编辑器程序。该程序不仅能够打开并显示文本文件的内容及其路径,还集成了菜单和工具栏功能,为用户提供更加便捷的操作体验。通过本案例的学习,读者可以深入了解文本编辑器的核心实现机制。 ... [详细]
  • PHP中元素的计量单位是什么? ... [详细]
  • 开发心得:深入探讨Servlet、Dubbo与MyBatis中的责任链模式应用
    开发心得:深入探讨Servlet、Dubbo与MyBatis中的责任链模式应用 ... [详细]
  • 如何将Java 8中的嵌套列表 List<List<Integer>> 转换为单一列表 List<Integer> 的操作方法
    本文详细探讨了如何在Java 8中将嵌套列表 `List` 展平为单一列表 `List` 的方法。通过使用流(Stream)API 和 `flatMap` 操作,可以高效地实现这一转换过程。该技术在处理多层数据结构时非常实用,适用于多种应用场景,如数据聚合和简化复杂列表操作。文章提供了详细的代码示例和解释,帮助开发者更好地理解和应用这一技术。 ... [详细]
  • 本文探讨了利用Java实现WebSocket实时消息推送技术的方法。与传统的轮询、长连接或短连接等方案相比,WebSocket提供了一种更为高效和低延迟的双向通信机制。通过建立持久连接,服务器能够主动向客户端推送数据,从而实现真正的实时消息传递。此外,本文还介绍了WebSocket在实际应用中的优势和应用场景,并提供了详细的实现步骤和技术细节。 ... [详细]
  • 掌握Android UI设计:利用ZoomControls实现图片缩放功能
    本文介绍了如何在Android应用中通过使用ZoomControls组件来实现图片的缩放功能。ZoomControls提供了一种简单且直观的方式,让用户可以通过点击放大和缩小按钮来调整图片的显示大小。文章详细讲解了ZoomControls的基本用法、布局设置以及与ImageView的结合使用方法,适合初学者快速掌握Android UI设计中的这一重要功能。 ... [详细]
  • Java SE 文件操作类详解与应用
    ### Java SE 文件操作类详解与应用#### 1. File 类##### 1.1 File 类概述File 类是 Java SE 中用于表示文件和目录路径名的对象。它提供了丰富的方法来操作文件和目录,包括创建、删除、重命名文件,以及获取文件属性和信息。通过 File 类,开发者可以轻松地进行文件系统操作,如检查文件是否存在、读取文件内容、列出目录下的文件等。此外,File 类还支持跨平台操作,确保在不同操作系统中的一致性。 ... [详细]
  • Pentaho Data Integration 中 BaseStep 类 getOutputRowSets 方法详解与代码实例 ... [详细]
  • 本项目在Java Maven框架下,利用POI库实现了Excel数据的高效导入与导出功能。通过优化数据处理流程,提升了数据操作的性能和稳定性。项目已发布至GitHub,当前最新版本为0.0.5。该项目不仅适用于小型应用,也可扩展用于大型企业级系统,提供了灵活的数据管理解决方案。GitHub地址:https://github.com/83945105/holygrail,Maven坐标:`com.github.83945105:holygrail:0.0.5`。 ... [详细]
author-avatar
mobiledu2502899727
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有