相信Java8的Stream 大家都已听说过了,但是可能大家不会用或者用的不熟,文章将带大家从零开始使用,循序渐进,带你走向Stream的巅峰。

操作符

什么是操作符呢?操作符就是对数据进行的一种处理工作,一道加工程序;就好像工厂的工人对流水线上的产品进行一道加工程序一样。

Stream的操作符大体上分为两种:中间操作符和终止操作符

中间操作符

对于数据流来说,中间操作符在执行制定处理程序后,数据流依然可以传递给下一级的操作符。

中间操作符包含8种(排除了parallel,sequential,这两个操作并不涉及到对数据流的加工操作):

  • map(mapToInt,mapToLong,mapToDouble) 转换操作符,把比如A->B,这里默认提供了转int,long,double的操作符。

  • flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作比如把 int[]{2,3,4} 拍平 变成 2,3,4 也就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,double的操作符。

  • limit 限流操作,比如数据流中有10个 我只要出前3个就可以使用。

  • distint 去重操作,对重复元素去重,底层使用了equals方法。

  • filter 过滤操作,把不想要的数据过滤。

  • peek 挑出操作,如果想对数据进行某些操作,如:读取、编辑修改等。

  • skip 跳过操作,跳过某些元素。

  • sorted(unordered) 排序操作,对元素排序,前提是实现Comparable接口,当然也可以自定义比较器。

终止操作符

数据经过中间加工操作,就轮到终止操作符上场了;终止操作符就是用来对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次。

  • collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的Collectors 提供了非常多收集器,可以说Stream 的核心在于Collectors。

  • count 统计操作,统计最终的数据个数。

  • findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional。

  • noneMatch、allMatch、anyMatch 匹配操作,数据流中是否存在符合条件的元素 返回值为bool 值。

  • min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值。

  • reduce 规约操作,将整个数据流的值规约为一个值,count、min、max底层就是使用reduce。

  • forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了。

  • toArray 数组操作,将数据流的元素转换成数组。

这里只介绍了Stream,并没有涉及到IntStream、LongStream、DoubleStream,这三个流实现了一些特有的操作符,我将在后续文章中介绍到。

说了这么多,只介绍这些操作符还远远不够;俗话说,实践出真知。那么,Let‘s go。

代码演练

Stream 的一系列操作必须要使用终止操作,否者整个数据流是不会流动起来的,即处理操作不会执行。

  • map,可以看到 map 操作符要求输入一个Function的函数是接口实例,功能是将T类型转换成R类型的。

map操作将原来的单词 转换成了每个单的长度,利用了String自身的length()方法,该方法返回类型为int。这里我直接使用了lambda表达式,关于lambda表达式 还请读者们自行了解吧。

public class Main {public static void main(String[] args) {Stream.of("apple","banana","orange","waltermaleon","grape").map(e->e.length()) //转成单词的长度 int.forEach(e->System.out.println(e)); //输出}
}

当然也可以这样,这里使用了成员函数引用,为了便于读者们理解,后续的例子中将使用lambda表达式而非函数引用。

public class Main {public static void main(String[] args) {Stream.of("apple","banana","orange","waltermaleon","grape").map(String::length) //转成单词的长度 int.forEach(System.out::println);}
}

结果如图:

  • mapToInt 将数据流中得元素转成Int,这限定了转换的类型Int,最终产生的流为IntStream,及结果只能转化成int。

public class Main {public static void main(String[] args) {Stream.of("apple", "banana", "orange", "waltermaleon", "grape").mapToInt(e -> e.length()) //转成int.forEach(e -> System.out.println(e));}
}

mapToInt如图:

  • mapToLong、mapToDouble 与mapToInt 类似

public class Main {public static void main(String[] args) {Stream.of("apple", "banana", "orange", "waltermaleon", "grape").mapToLong(e -> e.length()) //转成long ,本质上是int 但是存在类型自动转换.forEach(e -> System.out.println(e));}
}

mapToLong 如图:

public class Main {public static void main(String[] args) {Stream.of("apple", "banana", "orange", "waltermaleon", "grape").mapToDouble(e -> e.length()) //转成Double ,自动类型转换成Double.forEach(e -> System.out.println(e));}
}

mapToDouble如图:

  • flatmap 作用就是将元素拍平拍扁 ,将拍扁的元素重新组成Stream,并将这些Stream 串行合并成一条Stream

public class Main {public static void main(String[] args) {Stream.of("a-b-c-d","e-f-i-g-h").flatMap(e->Stream.of(e.split("-"))).forEach(e->System.out.println(e));}
}

flatmap 如图:

  • flatmapToInt、flatmapToLong、flatmapToDouble 跟flatMap 都类似的,只是类型被限定了,这里就不在举例子了。

  • limit 限制元素的个数,只需传入 long 类型 表示限制的最大数

public class Main {public static void main(String[] args) {Stream.of(1,2,3,4,5,6).limit(3) //限制三个.forEach(e->System.out.println(e)); //将输出 前三个 1,2,3}
}

limit如图:

public class Main {public static void main(String[] args) {Stream.of(1,2,3,1,2,5,6,7,8,0,0,1,2,3,1).distinct() //去重.forEach(e->System.out.println(e));}
}

distinct 如图:

  • filter 对某些元素进行过滤,不符合筛选条件的将无法进入流的下游

public class Main {public static void main(String[] args) {Stream.of(1,2,3,1,2,5,6,7,8,0,0,1,2,3,1).filter(e->e>=5) //过滤小于5的.forEach(e->System.out.println(e));}
}

filter 如图:

  • peek 挑选 ,将元素挑选出来,可以理解为提前消费

public class Main {public static void main(String[] args) {User w = new User("w",10);User x = new User("x",11);User y = new User("y",12);Stream.of(w,x,y).peek(e->{e.setName(e.getAge()+e.getName());}) //重新设置名字 变成 年龄+名字.forEach(e->System.out.println(e.toString()));}static class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}}}

peek 如图:

  • skip 跳过 元素

public class Main {public static void main(String[] args) {Stream.of(1,2,3,4,5,6,7,8,9).skip(4) //跳过前四个.forEach(e->System.out.println(e)); //输出的结果应该只有5,6,7,8,9}
}

skip 如图:

  • sorted 排序 底层依赖Comparable 实现,也可以提供自定义比较器

这里Integer 实现了比较器

public class Main {public static void main(String[] args) {Stream.of(2,1,3,6,4,9,6,8,0).sorted().forEach(e->System.out.println(e));}
}

sorted 默认比较器如图:

这里使用自定义比较,当然User 可以实现Comparable 接口

public class Main {public static void main(String[] args) {User x = new User("x",11);User y = new User("y",12);User w = new User("w",10);Stream.of(w,x,y).sorted((e1,e2)->e1.age>e2.age?1:e1.age==e2.age?0:-1).forEach(e->System.out.println(e.toString()));}static class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}}}

如图:

  • collect 收集,使用系统提供的收集器可以将最终的数据流收集到List,Set,Map等容器中。关注公众号互联网架构师,回复关键字2T,获取最新架构视频。

这里我使用collect 将元素收集到一个set中

public class Main {public static void main(String[] args) {Stream.of("apple", "banana", "orange", "waltermaleon", "grape").collect(Collectors.toSet()) //set 容器.forEach(e -> System.out.println(e));}
}

咦?,不是说终止操作符只能使用一次吗,为什么这里调用了forEach 呢?

forEach不仅仅是是Stream 中得操作符还是各种集合中得一个语法糖,不信咋们试试。

public class Main {public static void main(String[] args) {Set<String> stringSet = Stream.of("apple", "banana", "orange", "waltermaleon", "grape").collect(Collectors.toSet()); //收集的结果就是setstringSet.forEach(e->System.out.println(e)); set的语法糖forEach
}

结果如图:

  • count 统计数据流中的元素个数,返回的是long 类型

public class Main {public static void main(String[] args) {long count = Stream.of("apple", "banana", "orange", "waltermaleon", "grape").count();System.out.println(count);}
}

count 如图:

  • findFirst 获取流中的第一个元素

这里找到第一个元素 apple

public class FindFirst {public static void main(String[] args) {Optional<String> stringOptional = Stream.of("apple", "banana", "orange", "waltermaleon", "grape").findFirst();stringOptional.ifPresent(e->System.out.println(e));}
}

findFirst 结果如图:

  • findAny 获取流中任意一个元素

public class FindAny {public static void main(String[] args) {Optional<String> stringOptional = Stream.of("apple", "banana", "orange", "waltermaleon", "grape").parallel().findAny(); //在并行流下每次返回的结果可能一样也可能不一样stringOptional.ifPresent(e->System.out.println(e));}
}

findAny 在并行流下 使用结果:

输出了orange

输出了banana

  • noneMatch 数据流中得没有一个元素与条件匹配的

这里 的作用是是判断数据流中 一个都没有与aa 相等元素 ,但是流中存在 aa ,所以最终结果应该是false。关注公众号互联网架构师,回复关键字2T,获取最新架构视频

public class NoneMatch {public static void main(String[] args) {boolean result = Stream.of("aa","bb","cc","aa").noneMatch(e->e.equals("aa"));System.out.println(result);}
}

noneMatch 如图:

  • allMatch和anyMatch 一个是全匹配,一个是任意匹配 和noneMatch 类似,这里就不在举例了。

  • min 最小的一个,传入比较器,也可能没有(如果数据流为空)

public class Main {public static void main(String[] args) {Optional<Integer> integerOptional = Stream.of(0,9,8,4,5,6,-1).min((e1,e2)->e1.compareTo(e2));integerOptional.ifPresent(e->System.out.println(e));}

min如图:

  • max 元素中最大的,需要传入比较器,也可能没有(流为Empty时)

public class Main {public static void main(String[] args) {Optional<Integer> integerOptional = Stream.of(0,9,8,4,5,6,-1).max((e1,e2)->e1.compareTo(e2));integerOptional.ifPresent(e->System.out.println(e));}
}

max 如图:

  • reduce 是一个规约操作,所有的元素归约成一个,比如对所有元素求和,乘啊等。

这里实现了一个加法,指定了初始化的值

public class Main {public static void main(String[] args) {int sum = Stream.of(0,9,8,4,5,6,-1).reduce(0,(e1,e2)->e1+e2);System.out.println(sum);}
}

reduce 如图:

  • forEach

forEach 其实前就已经见过了,对每个数据遍历迭代

  • forEachOrdered 适用用于并行流的情况下进行迭代,能保证迭代的有序性

这里通过并行的方式输出数字

public class ForEachOrdered {public static void main(String[] args) {Stream.of(0,2,6,5,4,9,8,-1).parallel().forEachOrdered(e->{System.out.println(Thread.currentThread().getName()+": "+e);});}
}

forEachOrdered 如图:

  • toArray 转成数组,可以提供自定义数组生成器

public class ToArray {public static void main(String[] args) {Object[] objects=Stream.of(0,2,6,5,4,9,8,-1).toArray();for (int i = 0; i < objects.length; i++) {System.out.println(objects[i]);}}
}

toArray 如图:

总结

Java8 Stream就带大家认识到这里,如果你能跟着我的文章把每一个例子都敲一遍,相信都能掌握这些操作符的初步用法。

作者:litesky

来源:www.jianshu.com/p/11c925cdba50

带你认识不一样的Stream,Java8就该这么玩!相关推荐

  1. java iterable stream,java8 转换Iterable 至 Stream

    java8 转换Iterable 至 Stream 本文简要介绍在java8中转换java Iterable对象至Stream,利用Stream执行标准操作. 1.转换Iterable 至 Strea ...

  2. 这10本硬核技术书,带你读懂5G、物联网和边缘计算,玩转元宇宙

    导读:2022开年,元宇宙可能是当前最火的科技概念.作为元宇宙的技术支撑,5G和物联网将逐步成为新时代的"基础设施".今天为大家推荐10本关于5G.物联网以及边缘计算的硬核技术书. ...

  3. Java8初体验(二)Stream语法详解(转)

    本文转自http://ifeve.com/stream/ Java8初体验(二)Stream语法详解 感谢同事[天锦]的投稿.投稿请联系 tengfei@ifeve.com 上篇文章Java8初体验( ...

  4. java8/Stream流式计算从入门到精通/函数式编程实战

    摘要:Stream流式计算,本文讲解了Stream流式计算的概念,具体的使用步骤以及源码实现,最后讲解了使用Stream过程中需要注意的事项.Stream在公司项目中被频繁使用,在性能优化上具有广泛的 ...

  5. JAVA8 新特性-Lamda跟Stream

    JAVA8 新特性-Lamda跟Stream 主要内容 Lambda 表达式 函数式接口 方法引用与构造器引用 Stream API 接口中的默认方法与静态方法 新时间日期 API 其他新特性 Jav ...

  6. 【Java8新特性】关于Java8的Stream API,看这一篇就够了!!

    写在前面 Java8中有两大最为重要的改变.第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*)  ,那什么是Stream API呢?Java8中 ...

  7. java8 stream index_Java8 Stream基本使用

    1. 什么是Stream Stream是一个数据处理接口,本身不存储任何数据.大概有20多个方法,每个都很好用,并且含有函数式编程里的filter,map,reduce方法.Stream的数据有三个来 ...

  8. java8的stream特性_Java8新特性介绍:Stream API

    Stream API 了解Stream Java8中有两个比较大的改变 Lambda表达式 Stream API (java.util.stream.*) Stream是Java8中处理集合的关键抽象 ...

  9. Java8新特性学习(lambda,函数式接口,stream,Optional)

    一. Lambda Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递).可以写出更简洁.更灵活的代码.作为一种更紧凑的代码风格,使Jav ...

  10. Java8函数式编程详解

    Java8 函数式编程详解 Author:Dorae Date:2017年11月1日23:03:26 转载请注明出处 说起Java8,可能很多人都已经知道其最大的改进,就是引入了Lambda表达式与S ...

最新文章

  1. 华为机考HJ8合并表记录
  2. 为什么很多人喜欢把软件装在D盘,而不是系统盘C
  3. 2、AD工程创建步骤
  4. java 实现按规则自增功能_java运算符详解 - osc_74vaali6的个人空间 - OSCHINA - 中文开源技术交流社区...
  5. HDU 2242 双连通分量 考研路茫茫——空调教室
  6. pandas中size方法_如何使用pdpipe与Pandas构建管道?
  7. JavaScript-操作DOM对象-获得dom节点
  8. 内部服务器如何提供访问服务
  9. [考试]20151008
  10. PAT 1045 快速排序(25)(STL-set+思路+测试点分析)
  11. 小米手机浏览器部分图片显示异常
  12. GB 9706.1-2020| IEC 60601-1附录A关于条款6.3 的IP2X解释可能有错误
  13. postman Could not send request
  14. 自步学习-Self-paced Learning
  15. Java实现 LeetCode 55 跳跃游戏
  16. 【爬虫+数据清洗+可视化分析】用Python分析哔哩哔哩“阳了“的评论数据
  17. 个人注册域名需要注意哪些方面?
  18. BUUCTF-WEB(1-16)
  19. socket 通信 error:88
  20. Opencascade可视化--视图渲染流程分析

热门文章

  1. Centos7.2下安装redis通用键值命令
  2. 学习笔记#工作日志使用
  3. 关于Apache与Nginx的优势比较
  4. mysql的binary安装
  5. MindNode 5 for Mac(思维导图)中文版
  6. 如何在 Mac 上的照片中创建幻灯片?
  7. Ps 初学者教程,如何在图片中创建新背景?
  8. Mac高效笔记软件GoodNotes 5
  9. 常见的Java基础的面试题
  10. FQDN(Fully qualified domain name)