热门标签 | 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中。


推荐阅读
  • 本文讨论了在shiro java配置中加入Shiro listener后启动失败的问题。作者引入了一系列jar包,并在web.xml中配置了相关内容,但启动后却无法正常运行。文章提供了具体引入的jar包和web.xml的配置内容,并指出可能的错误原因。该问题可能与jar包版本不兼容、web.xml配置错误等有关。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • Commit1ced2a7433ea8937a1b260ea65d708f32ca7c95eintroduceda+Clonetraitboundtom ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 大数据Hadoop生态(20)MapReduce框架原理OutputFormat的开发笔记
    本文介绍了大数据Hadoop生态(20)MapReduce框架原理OutputFormat的开发笔记,包括outputFormat接口实现类、自定义outputFormat步骤和案例。案例中将包含nty的日志输出到nty.log文件,其他日志输出到other.log文件。同时提供了一些相关网址供参考。 ... [详细]
  • 本文介绍了如何在Jquery中通过元素的样式值获取元素,并将其赋值给一个变量。提供了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社区 版权所有