1: 概述

1.1 优势

1.2 与传统迭代器的区分

1.3 流的操作类型分为两种:

2:流的构造与转换

2:1 常见构造

2.2: 三大包装类型的构造

2.3 并行流的规则输出

2.4 流的转换

3:流操作

3.1 操作分类

3.2 Map 映射

3.3 Filter 过滤器

3.4 Foreach Peek(Intermediate) 输出

3.5 finalFist  findAny

3.6 Reduce

3.7 limit/skip

3.8 排序 Sorted

3.9min/max/distinct

3.10 Match

4生成流

4.1 generate

自定义Supplier

4.2 Iterator

5.聚合操作

5.1 groupingBy/partitioningBy

记录:

  1. 操作集合有Collections工具类
  2. 为了配合collect() 函数 配置了Collectors工具类
  3. Compartor类定义了 naturalOrder() reverseOrder() 前者为正序 后者为反序
  4. 为了解决流处理的NPE 增加了Optional工具类
  5. 为了并发处理数据增加了Spliterator工具类

1: 概述

  1.1 优势

Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序

  1.2 与传统迭代器的区分

传统迭代器是单向处理,数据按照一个方向流动,当然LisT的Iterator 提供了加强版本:

   Stream 可以并行化操作,迭代器只能命令式地、串行化操作

  原理实现:Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。Java 的并行 API 演变历程基本如下:

  • 1.0-1.4 中的 java.lang.Thread
  • 5.0 中的 java.util.concurrent
  • 6.0 中的 Phasers 等
  • 7.0 中的 Fork/Join 框架
  • 8.0 中的 Lambda

 1.3 流的操作类型分为两种:

Intermediate(中间操作 不触发操作 Lambda延迟性):一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射 / 过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。

Terminal(终止操作 触发整个流的操作):一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用 “光” 了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。

还有一种操作被称为 short-circuiting。用以指:

对于一个 intermediate 操作,如果它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream。

对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。

      划重点:

       Stream 的每个元素进行转换,而且是执行多次,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成. 这样时间复杂度就是 N(N为操作的具体的个数)

2:流的构造与转换

2:1 常见构造

// 1. Individual values
Stream stream = Stream.of("a", "b", "c");
// 2. Arrays
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 3. Collections
List<String> list = Arrays.asList(strArray);
stream = list.stream();

2.2: 三大包装类型的构造

可以使用 Stream<Integer>   Stream<Double>   Stream<Long> 但是 Boxing unboxing (装箱 拆箱非常耗时)

IntStream ints = IntStream.of(,,);
LongStream longs = LongStream.of(,,);
DoubleStream doubles = DoubleStream.of(,,); IntStream.range(, ).forEach(System.out::print);// [1,10) 区间
System.out.println();
IntStream.rangeClosed(, ).forEach(System.out::print);//[1,10] 区间

2.3 并行流的规则输出

parallel() 方法将普通流转换为并行流

 IntStream.range(, ).parallel().forEach(System.out::print); // 并行执行 效率高 但是输出结果不具备输入结果的有序性
IntStream.range(, ).parallel().forEachOrdered(System.out::print);// 并行执行 效率高 严格要求输出结果按照输入结果预定

     2.4 流的转换

collect() 方法

// 1. Array
String[] strArray1 = stream.toArray(String[]::new);
// 2. Collection
List<String> list1 = stream.collect(Collectors.toList());
List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
Set set1 = stream.collect(Collectors.toSet());
Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
// 3. String
String str = stream.collect(Collectors.joining()).toString();

注意: 一个Stream只能使用一次,terminal终结最后的操作

3:流操作

3.1 操作分类

  • Intermediate =>返回新的Stream

Filter  Map(FatMap,MapToXXmap)  Sorted()  limit()   skip   distinct  peek   sequential、 unordered

  • Terminal       => 终结操作

ForEach  ForOrderEach  Max  Min Collect    count   toArray、 reduce、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

  • shorting-circuing ==> 即可终结操作  也可以返回新的Stream

findFisrt  findAny   AnyMatch AllMatch NoneMatch  limit

3.2 Map 映射

参数为Function<T,R> 可以理解为转换流

// 一对一
IntStream.of(,,).map(x->x*).forEach(System.out::println);
// 合并流
Stream<List<Integer>> inputStream = Stream.of(
Arrays.asList(),
Arrays.asList(,),
Arrays.asList(,,));
Stream<Integer> child_stream = inputStream.flatMap(x->x.stream());
// 合并流到其他类型 一对多
DoubleStream doubleStream = inputStream.flatMapToDouble(x->x.stream().mapToDouble(Double::new));
IntStream intStream = inputStream.flatMapToInt(x->x.stream().mapToInt(Integer::new));
LongStream longStream = inputStream.flatMapToLong(x->x.stream().mapToLong(Long::new));
// 转大小写
List<String> output = wordList.stream().map(String::toUpperCase)
.collect(Collectors.toList());
// 平方数
List<Integer> nums = Arrays.asList(, , , );
List<Integer> squareNums = nums.stream().
map(n -> n * n).
collect(Collectors.toList());

3.3 Filter 过滤器

参数为Predicate 结果集为返回true的集合

//留下偶数
IntStream.range(, ).filter(x->(x&)==).forEach(System.out::println); Integer[] sixNums = {, , , , , };
Integer[] array = Stream.of(sixNums).filter(x->(x&)==).toArray(Integer[]::new);
// 把单词挑出来
List<String> output = reader.lines().
flatMap(line -> Stream.of(line.split(REGEXP))).
filter(word -> word.length() > ).
collect(Collectors.toList());

3.4 Foreach Peek(Intermediate) 输出

终结操作用于输出 ,一个流只能用一次

forEachOrdered  在并行情况为保证一定有序输出. Peek 内部参数 Consumer 执行操作后 返回一个新的Stream

 Stream<List<Integer>> stream = Stream.of(Arrays.asList(,,,,,));

        stream.parallel().forEach(System.out::println);
stream.parallel().forEachOrdered(System.out::println); //并行 强制有序
// 体现了 访问者设计模式
Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > )
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
// 输出
Filtered value: three
Mapped value: THREE
Filtered value: four
Mapped value: FOUR

   3.5 finalFist  findAny

返回Optional 非终结操作,可以结果继续处理 使用它的目的是尽可能避免 NullPointerException。 indAny、max/min、reduce 等方法等返回 Optional 值

Integer[] sixNums = {, , , , , };
Stream.of(sixNums).findFirst().ifPresent(System.out::println); Stream.of(sixNums).findAny().ifPresent(System.out::println);
// 返回的Optional 可以加上逻辑排除NPE
Integer else1 = Stream.of(sixNums).filter(x->x<).findAny().orElse(null);
System.out.println(else1);
// findFisrt findAny 找不到元素抛出NPE 可以加上Or系列方法 返回默认值

  3.6 Reduce

这个方法的主要作用是把   identity 作为第二个参数BinaryOperator 函数的输入,执行操作后返回

T reduce(T identity, BinaryOperator<T> accumulator);

规则:

只有一个参数的时候BinaryOperator 返回Optional

具有两个参数的时候则返回一个具体的运算结果

// 字符串连接,concat = "ABCD"
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
// 求最小值,minValue = -3.0
double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
// 求和,sumValue = 10, 有起始值
int sumValue = Stream.of(, , , ).reduce(, Integer::sum);
// 求和,sumValue = 10, 无起始值
sumValue = Stream.of(, , , ).reduce(Integer::sum).get();
// 过滤,字符串连接,concat = "ace"
concat = Stream.of("a", "B", "c", "D", "e", "F").
filter(x -> x.compareTo("Z") > ).
reduce("", String::concat);

以上 字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce

  3.7 limit/skip

limit 返回 Stream 的前面 n 个元素;skip 则是扔掉前 n 个元素

public void testLimitAndSkip() {
List<Person> persons = new ArrayList();
for (int i = ; i <= ; i++) {
Person person = new Person(i, "name" + i);
persons.add(person);
}
List<String> personList2 = persons.stream().map(Person::getName).limit().skip().collect(Collectors.toList());
System.out.println(personList2);
}
private class Person {
//get set
}

注意:

limit/skip ,放在Sorted()后面并不能影响排序的次数

有一种情况是 limit/skip 无法达到 short-circuiting 目的的,就是把它们放在 Stream 的排序操作后,原因跟 sorted 这个 intermediate 操作有关:此时系统并不知道 Stream 排序后的次序如何,所以 sorted 中的操作看上去就像完全没有被 limit 或者 skip 一样

并行流情况下不能使用Limit() 将会影响并行操作的次序性能

对一个 parallel 的 Steam 管道来说,如果其元素是有序的,那么 limit 操作的成本会比较大,因为它的返回对象必须是前 n 个也有一样次序的元素。取而代之的策略是取消元素间的次序,或者不要用 parallel Stream

3.8 排序 Sorted

List<Person> persons = new ArrayList();
for (int i = ; i <= ; i++) {
Person person = new Person(i, "name" + i);
persons.add(person);
}
List<Person> personList2 = persons.stream().limit().sorted((p1, p2) -> p1.getName().compareTo(p2.getName())).collect(Collectors.toList());
System.out.println(personList2);

3.9min/max/distinct

用 findFirst 来实现,但前者的性能会更好,为 O(n),而 sorted 的成本是 O(n log n)。同时它们作为特殊的 reduce 方法被独立出来也是因为求最大最小值是很常见的操作

Stream<Integer> stream = Stream.generate(()->new Random().nextInt()).limit();

        long nums = -stream.distinct().count();
System.out.println(nums);
Integer max = stream.max(Comparator.naturalOrder()).get();
Integer min = stream.min(Comparator.naturalOrder()).get();

3.10 Match

Stream 有三个 match 方法,从语义上说:

allMatch:Stream 中全部元素符合传入的 predicate,返回 true

anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true

noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true

List<Person> persons = new ArrayList();
persons.add(new Person(, "name" + , ));
persons.add(new Person(, "name" + , ));
persons.add(new Person(, "name" + , ));
persons.add(new Person(, "name" + , ));
persons.add(new Person(, "name" + , ));
boolean isAllAdult = persons.stream().
allMatch(p -> p.getAge() > );
System.out.println("All are adult? " + isAllAdult);
boolean isThereAnyChild = persons.stream().
anyMatch(p -> p.getAge() < );
System.out.println("Any child? " + isThereAnyChild);

4生成流

4.1 generate

Supplier 接口,你可以自己来控制流的生成。这种情形通常用于随机数、常量的 Stream,或者需要前后元素间维持着某种状态信息的 Stream.

generate 内部维护一个无限制的循环 根据传入的规则生成数据

需要使用Limit限制数据生成的范围

Random seed = new Random();
Supplier<Integer> random = seed::nextInt;
Stream.generate(random).limit().forEach(System.out::println);
//Another way
IntStream.generate(() -> (int) (System.nanoTime() % )).
limit().forEach(System.out::println);

自定义Supplier

Stream<Person> stream2 = Stream.generate(new Use_Max_Min_Distinct().new PersonSupplier()).limit();
stream2.forEach(System.out::println); private class PersonSupplier implements Supplier<Person>{
private Random random=new Random();
@Override
public Person get() {
return new Person("Tom",random.nextInt());
}
}
private class Person{
private String name;
// Constructor get set toString()
}

4.2 Iterator

iterate 跟 reduce 操作很像,接受一个种子值,和一个 UnaryOperator(例如 f)。

然后种子值成为 Stream 的第一个元素,f(seed) 为第二个,f(f(seed)) 第三个,以此类推。

Stream.iterate(, n -> n + ).limit(). forEach(x -> System.out.print(x + " "));
// 0 3 6 9 12 15 18 21 24 27

在 iterate 时候管道必须有 limit 这样的操作来限制 Stream 大小。

5.聚合操作

5.1 groupingBy/partitioningBy

  1. groupingBy  参数Function 多值的聚合操作
  2. partitioningBy 参数Predicate true false 的单值操作
 List<Person> list = Arrays.asList(
new Person("Tom1", ),
new Person("Tom2", ),
new Person("Tom3", ),
new Person("Tom4", ),
new Person("Tom5", ),
new Person("Tom6", )
);
// 分类
Map<Integer, List<Person>> personGroups =
Stream.generate(new PersonSupplier()).limit()
.collect(Collectors.groupingBy(Person::getAge));
Stream<Entry<Integer, List<Person>>> stream = personGroups.entrySet().stream();
List<Entry<Integer, List<Person>>> list2 = stream.collect(Collectors.toList());
Iterator<Entry<Integer, List<Person>>> iterator = list2.iterator();
while(iterator.hasNext()) {
Entry<Integer, List<Person>> entry = iterator.next();
System.out.println(entry.getKey()+" "+entry.getValue());
}
// 按照断言划分
Map<Boolean, List<Person>> map = Stream.generate(new PersonSupplier()).limit()
.collect(Collectors.partitioningBy(x->x.getAge()>));
Stream<Entry<Boolean, List<Person>>> stream2 = map.entrySet().stream();
stream2.forEach((entry)->System.out.println(entry.getKey()+" "+entry.getValue()));
class PersonSupplier implements Supplier<Person>{
public Person get() {
return new Person("Tom"+new Random().nextInt() , new Random().nextInt());
};
}
class Person {}// Constructor get set ToString()

详解JAVA8Stream API {全}的更多相关文章

  1. 三张图片详解Asp.Net 全生命周期

    用三张图片详解Asp.Net 全生命周期 下面我们使用三张图片解析ASP.net的整个生命周期,我总感觉使用图片更加的清楚的说明这种问题,所以使用的这样方式 说明: 1  第一张图片从全局说明从客户端 ...

  2. String 字符串详解 / 常用API

    String 详解 / 常用API 简介 String 是不可改变的字符串序列.String 为字符串常量 StringBuilder 与StringBuffer 均为可改变的字符串序列.为字符串变量 ...

  3. API函数详解:API大全总目录(按字母排列)

    API函数详解 http://www.feiesoft.com/api/api.html

  4. 【JAVAEE学习笔记】hibernate01:简介、搭建、配置文件详解、API详解和CRM练习:保存客户

    今日学习:hibernate是什么 一.hibernate是什么 框架是什么: 1.框架是用来提高开发效率的 2.封装了好了一些功能.我们需要使用这些功能时,调用即可.不需要再手动实现. 3.所以框架 ...

  5. 细说show slave status参数详解(最全)【转】

    在搭建好mysql主从之后,我们一般在从库上通过命令 show slave status\G 来查看主从的状态,会有很多的参数,接下来笔者就带大家好好的了解这些参数 root@localhost (n ...

  6. JAVAEE学习——hibernate01:简介、搭建、配置文件详解、API详解和CRM练习:保存客户

    今日学习:hibernate是什么 一.hibernate是什么 框架是什么: 1.框架是用来提高开发效率的 2.封装了好了一些功能.我们需要使用这些功能时,调用即可.不需要再手动实现. 3.所以框架 ...

  7. 详解JAVA8Stream 方法引用(基础){全}

    1: Stream流 1.1 引言 1.2 流式思想概述 1.3 获取流 1.4 常用方法 1.5 练习:集合元素处理 2:方法引用 2.1 冗余的Lambda场景 2.2 方法引用符 2.3 通过对 ...

  8. 详解Java API之正则表达式

    正则表达式描述的是一种规则,符合这种限定规则的字符串我们认为它某种满足条件的,是我们所需的.在正则表达式中,主要有两种字符,一种描述的是普通的字符,另一种描述的是元字符.其中元字符是整个正则表达式的核 ...

  9. Android Widget工作原理详解(一) 最全介绍

    转载请标明出处:http://blog.csdn.net/sk719887916/article/details/46853033 ; Widget是安卓的一应用程序组件,学名窗口小部件,它是微型应用 ...

随机推荐

  1. 推荐系统| ② 离线推荐&基于隐语义模型的协同过滤推荐

    一.离线推荐服务 离线推荐服务是综合用户所有的历史数据,利用设定的离线统计算法和离线推荐算法周期性的进行结果统计与保存,计算的结果在一定时间周期内是固定不变的,变更的频率取决于算法调度的频率. 离线推 ...

  2. json解决ajax跨域的原理

    jsonp只能解决GET类型的ajax请求跨域问题 jsonp请求不是ajax请求,而是一般的get请求 基本原理 浏览器端: 动态生成<script>来请求后台接口(src就是接口的ur ...

  3. Centos7下Redis设置开机自启动服务

    有个同事说重启了服务器没有自启动redis,我看了一下,是以前手动编译安装的模式,没有配置开机启动的服务 这边做个笔记记录一下redis如何设置编译安装模式的开机自启动. 第一种方法: 1.编写red ...

  4. Cypress 之 常用API

    .visit() 访问一个远程URL.>>详情参考 Cypress 之 cy.visit() cy.visit(url) cy.visit(url, options) cy.visit(o ...

  5. Oracle - SPM固定执行计划(二)

    一.前言 前面文章(https://www.cnblogs.com/ddzj01/p/11365541.html)给大家介绍了当一条sql有多个执行计划时,如何通过spm去绑定其中一条执行计划.本文将 ...

  6. Difference between JDK, JRE and JVM

    With Java programming language, the three terms i.e. JDK, JRE and JVM will always be there to unders ...

  7. Spring Boot 2 快速教程:WebFlux 集成 Thymeleaf(五)

    号外:为读者持续整理了几份最新教程,覆盖了 Spring Boot.Spring Cloud.微服务架构等PDF.获取方式:关注右侧公众号"泥瓦匠BYSocket",来领取吧! 摘 ...

  8. Java并发专题

    ——参考于码农求职小助手公众号 1.并行和并发有什么区别? 1. 并行是指两个或者多个事件在同一时刻发生:而并发是指两个或多个事件在同一时间间隔发生: 2. 并行是在不同实体上的多个事件,并发是在同一 ...

  9. 自学_DOM<五>

    类库DOM DOM(document object medol)文档对象模型. DOM就是HTML页面的模型,将每个标签都做为一个对象,JavaScript通过调用DOM中的属性.方法就可以对网页中的 ...

  10. zabbix snmp监控与主被模式

    1.snmp基础介绍 snmp全称是简单网络管理协议 为什么要用? 路由器交换机无法安装agent程序,但是都提供snmp服务端, 我们可以使用zabbix的snmp方式监控snmp服务端的数据 2. ...