Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果

一、创建流

  1、 Collection接口有默认的stream方法,这个也就是大家平时用的list.stream(),只要是这个接口的实现类都可以通过这种方式去创建一个流

Lists.newArrayList().stream();

  2、Stream的静态方法

// 1、通过 build 方法创建

Stream.Builder builder = Stream.builder();

builder.accept(1);

builder.add(2);

Stream build = builder.build();
// 2、通过Stream.of 方法创建
// of有2个重载的方法,一个是接受一个对象,一个是接受可变参数创建流 Stream s1 = Stream.of(1); Stream s2 = Stream.of(1,2,3,4,5);
// 3、通过Stream.generate 静态方法去创建一个流。这个特别需要注意,这个方法是创建无限流,如果不在调用这个函数后调用limit方法去限制流的长度,则会无限创建下去

//  这里传入的行为参数一定是有返回值的,也就是行为的结果是创建了一个对象。
Stream generate = Stream.generate(Math::random).limit(10); Stream g2 = Stream.generate(() -> Math.random()).limit(10);
// 4、通过Stream.iterate 迭代的去创建流,同上也是无限流,不同的地方在于这个函数有2个参数,第一个参数是基值,第二个参数是基于第一个参数的运算函数。如下生成自然数序列

//  这里iterate,会迭代的进行第二个参数的运算,
 Stream limit = Stream.iterate(0, n -> n +1).limit(10);
 // 5、 Stream.empty()创建一个空的流
// 6、Stream.concat(arg1,arg2) 将2个流合并为一个流

二、函数

  1、toArray (IntFunction<A[]> generator)  这个方法是指定创建一个对象数组 ( 这个方法是将流中的数据转换为一个数组 )

  2、limit()函数:入参是一个long的基本类型。如果这个值的大小要超过本身流包含对象的长度,则以流对象长度为主。

   3、allMatch()函数 :

   1)、判断一个流中元素是否全部满足表达式的判定

   2)、入参是一个lamada表达式。这个lamada表达式式一个判断函数。流会将每一个对象进行表达式运算。最终返回一个布尔结果。
   3)、这个运算会在遇到第一个不满足的运算或者全部运算完成时候返回。
// 判断流中元素是否全部是偶数,当遇到第一个不满足条件的对象时候,直接返回false结果。如果全部是偶数,则会以此将所有对象比较完成,然后返回最终结果。
boolean b = Stream.of(2,4,6,8,9,10,12).allMatch(p -> {
System.out.println(p);
return p % 2 == 0;});
System.out.println(JSONObject.toJSONString(b));
输出结果如下
2 4 6 8 9 false

  4、 anyMatch() :判断一个流中是否有满足表达式的判定。如果遇到第一个满足的或者全部运算完成时返回  

// 判断流中元素是否有偶数,如果有,则直接返回true。后面的元素不会再进行比较。如果没有则会依次将每个对象比较完成后再返回最终结果。    
boolean b = Stream.of(2,4,6,8,9).anyMatch(p -> {
System.out.println(p);
return p % 2 == 0;});
System.out.println(JSONObject.toJSONString(b));
输出结果如下
2 true

  5、count() 返回流中对象的个数

  6、distinct() 对流中元素进行去重,返回一个流
  7、filter() 对流中的元素通过给定的表达式进行筛选,这里的结果不是筛选掉,而是筛选出 (即:不删除)
  8、findAny() 从字面含义上来看,是找出任意一个,但是经过多次实验,返回永远是流中的第一个元素。
  9、findFirst() 返回流中第一个元素,如下所示
  10、forEach() 和 forEachOrdered()  遍历流对象,通普通的for循环一样。从简单输出看,二者行为是一样的,foreach在于纯消费,没有返回值。

    Stream.of(2, 4, 6, 8, 9, 1, 3).forEach(System.out::print);
Stream.of(2, 4, 6, 8, 9, 1, 3).forEachOrdered(System.out::print);
如上输出都是流中元素的顺序。
那么二者的区别再哪里呢?看如下代码
ArrayList<Integer> integers = Lists.newArrayList(1, 3, 4, 22, 43, 65, 11, 23, 45, 35);
integers.parallelStream().forEach(System.out::print);
这里如果多次打印,就会发现,每次打印的顺序是不一样的
再看如下代码:
ArrayList<Integer> integers = Lists.newArrayList(1, 3, 4, 22, 43, 65, 11, 23, 45, 35);
integers.parallelStream().forEachOrdered(System.out::print);
这里经过多次打印,就是严格按照流中元素的顺序进行打印的。
如果需要并行处理100万数据,那么我们可以测试下,顺序流和非顺序流的耗时。先生成100万个数,然后用并行流进行顺序消费
再我512G固态,i7 8700k 3.7GHZcpu 16G内存情况下
public static void main(String[] args) {
List<Integer> collect = Stream.iterate(0, n -> n + 1).limit(1000000).collect(Collectors.toList());
for (int i = 0; i <10 ; i++) {
long l = System.currentTimeMillis();
collect.parallelStream().forEachOrdered(n-> System.out.print(""));
long l1 = System.currentTimeMillis();
System.out.println(l1-l);
}
}
分别耗时为下列ms。
78 47 46 47 31 48 85 61 47 62
如果将其中的forEachOrdered替换成forEach
94 78 63 62 78 81 66 85 63 78
性能反而不如顺序消费来的快。 从这个结果来看,二者差距并不大。选用哪个方法,完全依赖于是否需要顺序消费。

11、map()和flatmap()函数: map和flatmap函数入参都是一个Function函数。从函数上看二者不同在于,map函数是普通的表达式运算,而flatmap则是一个必须将表达式统一包装到一个流的表达式。

  1)、map函数式对流中的每一个元素进行遍历然后进行运算,返回一个新的流对象。这里需要注意,foreach也是遍历运算,区别在于foreach在于纯消费,没有返回值。而map是运算后将结果返回给新的流。
    List<String> strings = Lists.newArrayList("hello", "world","apple");
List<String> collect = strings.stream().map(s -> s += ":").collect(Collectors.toList());
System.out.println(strings);
System.out.println(collect);
输出入下:说明不影响原来的对象状态
[hello, world, apple]
[hello:, world:, apple:]

  2)、flatmap是一个处理更高纬度的操作。map函数只能处理一层纬度,返回的也是一层纬度。而flatmap可以处理多层纬度,然后返回一维。

     比如我们需要将一个二维list转换为1纬list。那么用flatmap通过一个很简单的函数就可以直接转换。

    List<List<String>> listList = Lists.newArrayList();
listList.add(Lists.newArrayList("apple", "mi","huawei"));
listList.add(Lists.newArrayList("dell", "lenvo","isony"));
listList.add(Lists.newArrayList("tmall", "jd","qq"));
List<Object> collect = listList.stream().flatMap(s -> s.stream()).collect(Collectors.toList());
System.out.println(JSONObject.toJSONString(collect));
输出结果如下:
["apple","mi","huawei","dell","lenvo","isony","tmall","jd","qq"]

    还是以上面的例子,那么如果我想继续拆成单个字母的数组呢?可以通过继续再进行一次flatmap运算即可。也就是flatmap的功能主要是将一个维度减少一层。

    List<Object> collect = listList.stream().
flatMap(s -> s.stream()).
flatMap(b -> Stream.of(b.split("|"))).
distinct().
collect(Collectors.toList());
System.out.println(JSONObject.toJSONString(collect));
输出结果如下:
["a","p","l","e","m","i","h","u","w","d","n","v","o","s","y","t","j","q"]

12、flatmapToDouble、int、long 是将对象直接映射成对于的类型:

  比如一系列特定分割符的字符串,(实际应用场景中,我们有一种场景是给用户设置限额,限额分为不同等级。和对应系统约定好限额配置规则,则只需要一行代码就可以解释完成。)

  

    List<String> strings = Lists.newArrayList("123/456","789/123","456/789");
double[] doubles = strings.stream().
flatMapToDouble(s -> Stream.of(s.split("/")).mapToDouble(e -> Double.valueOf(e))). toArray();
System.out.println(JSONObject.toJSONString(doubles));
输出结果如下:
[123.0,456.0,789.0,123.0,456.0,789.0]

13、max方法和min方法获取流中最大值最小值,这里可以传入自定义实现的Comparator实现类进行自定义排序。

     List<Integer> Integers = Lists.newArrayList(1,4,99,5,55,23);
Optional<Integer> max = Integers.stream().max((a,b) -> a.compareTo(b));
Optional<Integer> min = Integers.stream().min((a,b) -> a.compareTo(b));
System.out.println(JSONObject.toJSONString(max.get()));
System.out.println(JSONObject.toJSONString(min.get()));

14、noneMatch 判断是否都不匹配。如果是,则返回true,如果不是则返回false

     List<Integer> Integers = Lists.newArrayList(1,3,5,7);
boolean b = Integers.stream().noneMatch(a -> a % 2 == 0);
System.out.println(b);
  b结果为 true

15、peek 对流中元素做处理,不返回。对应和map区别,map会将处理返回,peek处理后不返回。

    List<Integer> collect = Stream.of(1, 3, 5, 6, 7).peek(a -> a = a + 1).collect(Collectors.toList());
System.out.println(JSONObject.toJSONString(collect));
输出结果如下:
[1,3,5,6,7]

16、skip函数,入参是一个long基本类型,效果是忽略流中指定个元素。如果超过流的长度,则会返回流

    List<Integer> collect = Stream.of(1, 3, 5, 6, 7).skip(7).collect(Collectors.toList());
System.out.println(JSONObject.toJSONString(collect));
输出结果如下:会把流中前7个元素全部忽略掉,所以输出一个空的数组
[]
List<Integer> collect = Stream.of(1, 3, 5, 6, 7).skip(2).collect(Collectors.toList());
System.out.println(JSONObject.toJSONString(collect));
输出结果如下: 会把前2个元素给忽略掉,然后返回后面的元素。
[5,6,7]

17、sorted,对流中元素进行排序。不指定排序方式,按照默认的方式排序。可以自定义排序方式

    List<Integer> collect = Stream.of(99, 5, 47, 34, 2).sorted().collect(Collectors.toList());
System.out.println(JSONObject.toJSONString(collect));
输出结果如下:
[2,5,34,47,99]

18、reduce函数 1:reduce(BinaryOperator<P_OUT> accumulator) :https://www.jianshu.com/p/35ab18451a52

JDK1.8 Stream的更多相关文章

  1. 使用jdk1.8 stream特性对参数名称进行排序

    在对外对接的时候,通常会碰到签名方式, 然后签名的时候,要求按照参数名称进行排序. 比如参数为 c=22&a=1, 需要将结果排序为a=1&c=22, 然后再进行别的运算. 可以使用j ...

  2. jdk1.8 Stream 特性总结

    不是数据结构 它没有内部存储,它只是用操作管道从 source(数据结构.数组.generator function.IO channel)抓取数据. 它也绝不修改自己所封装的底层数据结构的数据.例如 ...

  3. jdk1.8 -- stream 的使用

    一.stream介绍 stream 是jdk 一个加强的api操作,翻译过来就是流的意思,主要是对Collection 集合的一些操作,流一但生成就会有方向性,类似于自来水管的水流一样,不可以重复使用 ...

  4. java代码之美(12)---CollectionUtils工具类

    java代码之美(12)---CollectionUtils工具类 这篇讲的CollectionUtils工具类是在apache下的, 而不是springframework下的CollectionUt ...

  5. Java中List集合去除重复数据的六种方法

    1. 循环list中的所有元素然后删除重复 public static List removeDuplicate(List list) { for ( int i = 0 ; i < list. ...

  6. java代码(12) ---CollectionUtils工具类

    CollectionUtils工具类 CollectionUtils工具类是在apache下的,而不是springframework下的CollectionUtils 个人觉得在真实项目中Collec ...

  7. ForkJoinPool大型图文现场(一阅到底 vs 直接收藏)

    知识回顾 并发工具类我们已经讲了很多,这些工具类的「目标」是让我们只关注任务本身,并且忽视线程间合作细节,简化了并发编程难度的同时,也增加了很多安全性.工具类的对使用者的「目标」虽然一致,但每一个工具 ...

  8. Java进阶篇之十五 ----- JDK1.8的Lambda、Stream和日期的使用详解(很详细)

    前言 本篇主要讲述是Java中JDK1.8的一些新语法特性使用,主要是Lambda.Stream和LocalDate日期的一些使用讲解. Lambda Lambda介绍 Lambda 表达式(lamb ...

  9. JDK1.8新特性——Stream API

    JDK1.8新特性——Stream API 摘要:本文主要学习了JDK1.8的新特性中有关Stream API的使用. 部分内容来自以下博客: https://blog.csdn.net/icarus ...

随机推荐

  1. ES6入门系列 ----- 使用Proxy 实现观察者模式

    观察者模式是指函数自动观察数据对象的变化, 一旦对象有变化,函数就会自动执行. 它定义了一种一对多的依赖关系,我们用Proxy来实现一个简单的观察者模式(PS: 初学我们认为 观察者模式 == 发布订 ...

  2. Python创建virtualenv虚拟环境方法

    一.通过virtualenv软件创建 安装:        -pip3 install virtualenv    创建虚拟环境:        -(1)virtualenv wannings-ms- ...

  3. 常见的Dos命令大全

    打开cmd: Win键+R  输入cmd; 常用的Dos命令: 1.盘符切换: 2.打开文件目录:   dir 3.清理屏幕:  cls 4.退出: exit 5.查看本机IP地址:ipconfig ...

  4. c# 第20节 一维数据的冒泡排序

    本节内容: 1:冒泡排序说明: 2:冒泡排序实现: 3:冒泡排序的时间复杂度 1:冒泡排序说明: 冒泡排序也是最简单最基本的排序方法之一.冒泡排序的思想很简单,就是以此比较相邻的元素大小,将小的前移, ...

  5. 爬虫之爬取豆瓣图书名字及ID

    from urllib import request from bs4 import BeautifulSoup as bs #爬取豆瓣最受关注图书榜 resp = request.urlopen(' ...

  6. 【西北师大-2108Java】第二次作业成绩汇总

    2[西北师大-2108Java]第二次作业成绩汇总 以命令行方式或在Eclipse集成开发环境中编辑.编译.运行第3章示例程序3-1-3-5,结合程序运行结果理解程序代码,每个示例程序从语法.算法两个 ...

  7. 《为什么说Redis是单线程的以及Redis为什么这么快!》

    为什么说Redis是单线程的以及Redis为什么这么快!   一.前言 近乎所有与Java相关的面试都会问到缓存的问题,基础一点的会问到什么是“二八定律”.什么是“热数据和冷数据”,复杂一点的会问到缓 ...

  8. luoguP4094 [HEOI2016/TJOI2016]字符串

    题意 考虑二分答案\(mid\),现在我们要判断\(s[c...c+mid-1]\)是否在\(s[a...b]\)出现过. 首先找到\(s[c...c+mid-1]\)所在的状态: 建出\(paren ...

  9. Eclipse查看git中的历史,显示详细时间

    clipse show date details in git history我的eclipse查看git history,显示为相对时间,并不是很方便,想要查看某个具体日期的版本代码,就需要设置为具 ...

  10. mysql数据库的批量数据导入与导出,性能提升。

    少量数据批量导入:1. 先从数据库把唯一键的值查询出来,放在列表2. 将导入的数据遍历取出,看是否存在列表中,若不在,说明数据库没有.3. 定义两个空列表,一个做为插入数据,一个做为更新数据4. 步骤 ...