一、强大的Stream API

  除了Lambda表达式外,Java8另外一项重大更新便是位于java.util.stream.*下的Stream API

  Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对 集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数 据库查询。也可以使用 Stream API 来并行执行操作。简而言之, Stream API 提供了一种高效且易于使用的处理数据的方式。

  什么是Stream

  是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。 “集合讲的是数据,流讲的是计算!

  注意:

    ①Stream 自己不会存储元素。

    ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

    ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

  接下来从三个流程讲解Stream的用法:创建——中间操作——终止操作

  如何创建Stream

   通过Collection集合家族的方法创建流

       default Stream stream() : 返回一个顺序流

       default Stream parallelStream() : 返回一个并行流

    通过数组的静态方法(Arrays.stream())

    static Stream stream(T[] array): 返回一个流

    通过Stream的静态方法of()

     public static Stream of(T... values) : 返回一个流

  通过静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。

    迭代:public static Stream iterate(final T seed, final UnaryOperator f)

    生成: public static Stream generate(Supplier s) :

  对以上这些方式进行实例演示:

    @Test
public void test1() {
// 1.通过集合得到流
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
// 2.通过数组
Employee[] emps = new Employee[5];
Stream<Employee> stream1 = Arrays.stream(emps);
// 3.通过Stream的静态方法
Stream<String> stream2 = Stream.of("a", "b", "c");
// 4.通过Stream静态方法创建无限流
Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2);
Stream<Double> stream4 = Stream.generate(Math::random);
}

  中间操作

  多个中间操作可以连接起来形成一个流水线,除非流水 线上触发终止操作,否则中间操作不会执行任何的处理! 而在终止操作时一次性全部处理,称为“惰性求值”。

  大致可以分为:筛选与切片、映射、排序

  

  我们依旧i通过示例来了解这几个操作:(结果已经通过测试,不再赘述)

  // filter——通过Lambda表达式排除流中某些元素
@Test
public void test2() {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("小张", 18));
empList.add(new Employee("小明", 19));
empList.add(new Employee("小红", 20));
// 集合创建流
Stream<Employee> empStream = empList.stream().filter((e) -> e.getAge() > 18);
// 终止操作
empStream.forEach(System.out::println);
} // limit——截断流,使流不超过指定数量(与skip互补,暂不演示)
@Test
public void test3() {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("小张", 18));
empList.add(new Employee("小明", 19));
empList.add(new Employee("小红", 20));
// 注意这种写法
empList.stream().filter((e) -> e.getAge() < 20)
.limit(1)
.forEach(System.out::println);
}
// distinct——通过hashCode()和equals()实现去重
@Test
public void test4() {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("小张", 18));
empList.add(new Employee("小张", 18));
empList.add(new Employee("小红", 20));
// 去重操作
empList.stream()
.filter((e) -> e.getAge() < 19)
.distinct()
.forEach(System.out::println); }

  映射

  

   示例讲解:

// map——接收函数,将每个元素运用到函数上,映射为一个新的元素(flatMap见定义,不再赘述)
@Test
public void test5() {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("小张", 18));
empList.add(new Employee("小明", 19));
empList.add(new Employee("小红", 20));
// 映射操作,例如提取名字
empList.stream()
.map(Employee::getName)
.forEach(System.out::println); }

  排序

  

  示例讲解

    // sorted——可以按自然排序(无参)或相应的比较器排序(参数为比较器)
@Test
public void test6() {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("小明", 18));
empList.add(new Employee("小张", 19));
empList.add(new Employee("小红", 20));
// 注意Employee没有自然排序方式!
empList.stream()
.sorted((e1, e2) -> {
// 若年龄相等,比较姓名
if (e1.getAge().equals(e2.getAge())) {
return e1.getName().compareTo(e2.getName());
}
// 年龄不等,直接比较年龄(加上符号,逆向排序)
return -(e1.getAge().compareTo(e2.getAge()));
})
.forEach(System.out::println); }

  终止操作

  查找与匹配

  

  

// allMatch——检查是否全部匹配
// anyMatch——是否至少匹配一个
// noneMatch不再赘述
@Test
public void test7() {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("小明", 18, Status.FREE));
empList.add(new Employee("小张", 19, Status.VOCATION));
empList.add(new Employee("小红", 20, Status.FREE));
// 注意Employee没有自然排序方式!
boolean b1 = empList.stream()
.allMatch((e) -> e.getStatus().equals(Status.FREE));
System.out.println(b1);// false
boolean b2 = empList.stream()
.anyMatch((e) -> e.getStatus().equals(Status.VOCATION));
System.out.println(b2);// true
}
// findFirst——流中第一个元素
// findAny——返回任意元素
@Test
public void test8() {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("小明", 18, Status.FREE));
empList.add(new Employee("小张", 19, Status.VOCATION));
empList.add(new Employee("小红", 20, Status.FREE));
// 注意Employee没有自然排序方式!
Optional<Employee> op = empList.stream()
.sorted((e1, e2) -> e1.getAge().compareTo(e2.getAge()))
.findFirst();
// Java8中使用Optional来避免空指针,orElse表示若op元素为空,则使用另外元素替代
// op.orElse(new Employee("老王", 20, Status.FREE));
Employee employee = op.get();
System.out.println(employee); Optional<Employee> any = empList.stream()
.filter((e) -> e.getStatus().equals(Status.FREE))
.findAny();
}
// count、max、min有点类似SQL语句
@Test
public void test9() {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("小明", 18, Status.FREE));
empList.add(new Employee("小张", 19, Status.VOCATION));
empList.add(new Employee("小红", 20, Status.FREE));
// 这里省略了中间操作
long count = empList.stream()
.count();
Optional<Employee> max = empList.stream()
.max((e1, e2) -> {
if (e1.getAge().equals(e2.getAge())) {
return e1.getName().compareTo(e2.getName());
}
return e1.getAge().compareTo(e2.getAge());
});
Employee employee = max.get();
System.out.println(employee);
// 提取最小的工资数(结合之前的中间操作)
Optional<Integer> min = empList.stream()
.map(Employee::getAge)
.min(Integer::compare);
System.out.println(min.get());
}
// forEach之前已经使用到,不再赘述

  规约

  

  示例:

 // reduce——将集合中的元素反复结合起来,得到一个值
@Test
public void test10() {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("小张", 18));
empList.add(new Employee("小明", 19));
empList.add(new Employee("小红", 20)); // 例如,计算所有年龄总和(先将员工信息进行映射,提取age,也就是经典的map-reduce模式)
Integer totalAge = empList.stream()
.map(Employee::getAge)
.reduce(0, (x, y) -> x + y);// 第一个参数是起始值,第二个参数为二元运算的Function
System.out.println(totalAge);
}

  收集

  

  Collector 接口中方法的实现决定了如何对流执行收集操作(如收 集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态 方法,可以方便地创建常见收集器实例,

  示例

   // collect——常见的运用例如提取员工信息中的name,组装成新的集合等操作
@Test
public void test11() {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("小张", 18));
empList.add(new Employee("小明", 19));
empList.add(new Employee("小红", 20)); List<String> list = empList.stream()
.map(Employee::getName)
.collect(Collectors.toList());// 需要去重,请使用toSet();
list.forEach(System.out::println);
// 需要自定义集合,例如LinedHashSet,可以使用此方式
empList.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new));
}

  更多Collectors中的方法(例如couonting,grouping),可以参见下表或者在源码中参考

toList List<T> 把流中元素收集到List
List<Employee> emps= list.stream().collect(Collectors.toList());
toSet Set<T> 把流中元素收集到Set
Set<Employee> emps= list.stream().collect(Collectors.toSet());
toCollection Collection<T> 把流中元素收集到创建的集合
Collection<Employee>emps=list.stream().collect(Collectors.toCollection(ArrayList::new));
counting Long 计算流中元素的个数
long count = list.stream().collect(Collectors.counting());
summingInt Integer 对流中元素的整数属性求和
inttotal=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingInt Double 计算流中元素Integer属性的平均

doubleavg= list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingInt IntSummaryStatistics 收集流中Integer属性的统计值。
如:平均值
IntSummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joining String 连接流中每个字符串
String str= list.stream().map(Employee::getName).collect(Collectors.joining());
maxBy Optional<T> 根据比较器选择最大值
Optional<Emp>max= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minBy Optional<T> 根据比较器选择最小值
Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing 归约产生的类型 从一个作为累加器的初始值
开始,利用BinaryOperator与
流中元素逐个结合,从而归
约成单个值
inttotal=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));
collectingAndThen 转换函数返回的类型 包裹另一个收集器,对其结
果转换函数
inthow= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingBy Map<K, List<T>> 根据某属性值对流分组,属
性为K,结果为V
Map<Emp.Status, List<Emp>> map= list.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
partitioningBy Map<Boolean, List<T>> 根据true或false进行分区
Map<Boolean,List<Emp>>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage));

 二、并行流与串行流

  并行流就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流。

    原理——fork/join框架

  采用 “工作窃取”模式(work-stealing): 当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线 程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。

  更多fork/join相关的介绍,请参见:http://www.infoq.com/cn/articles/fork-join-introduction

  Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。

    Long sum = LongStream.rangeClosed(0L, 10000000000L)
.parallel()
.sum();

  完整的示例,请参见如下:

package com.atguigu.java8;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream; import org.junit.Test; public class TestForkJoin { @Test
public void test1(){
long start = System.currentTimeMillis(); ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinCalculate(0L, 10000000000L); long sum = pool.invoke(task);
System.out.println(sum); long end = System.currentTimeMillis(); System.out.println("耗费的时间为: " + (end - start)); //112-1953-1988-2654-2647-20663-113808
} @Test
public void test2(){
long start = System.currentTimeMillis(); long sum = 0L; for (long i = 0L; i <= 10000000000L; i++) {
sum += i;
} System.out.println(sum); long end = System.currentTimeMillis(); System.out.println("耗费的时间为: " + (end - start)); //34-3174-3132-4227-4223-31583
} @Test
public void test3(){
long start = System.currentTimeMillis(); Long sum = LongStream.rangeClosed(0L, 10000000000L)
.parallel()
.sum(); System.out.println(sum); long end = System.currentTimeMillis(); System.out.println("耗费的时间为: " + (end - start)); //2061-2053-2086-18926
} }

Java8新特性(二)——强大的Stream API的更多相关文章

  1. Java8 新特性2——强大的Stream API

    强大的Stream API Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找.过滤和映射数据等操作.简而言之,Stream API 提供 ...

  2. Java8新特性第3章(Stream API)

    Stream作为Java8的新特性之一,他与Java IO包中的InputStream和OutputStream完全不是一个概念.Java8中的Stream是对集合功能的一种增强,主要用于对集合对象进 ...

  3. java8新特性-lambda表达式和stream API的简单使用

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

  4. Java8 新特性之集合操作Stream

    Java8 新特性之集合操作Stream Stream简介 Java 8引入了全新的Stream API.这里的Stream和I/O流不同,它更像具有Iterable的集合类,但行为和集合类又有所不同 ...

  5. Java8 新特性之Stream----java.util.stream

    这个包主要提供元素的streams函数操作,比如对collections的map,reduce. 例如: int sum = widgets.stream() .filter(b -> b.ge ...

  6. Java8新特性时间日期库DateTime API及示例

    Java8新特性的功能已经更新了不少篇幅了,今天重点讲解时间日期库中DateTime相关处理.同样的,如果你现在依旧在项目中使用传统Date.Calendar和SimpleDateFormat等API ...

  7. Java8新特性之方法引用&Stream流

    Java8新特性 方法引用 前言 什么是函数式接口 只包含一个抽象方法的接口,称为函数式接口. 可以通过 Lambda 表达式来创建该接口的对象.(若 Lambda 表达式抛出一个受检异常(即:非运行 ...

  8. Java8新特性(1)—— Stream集合运算流入门学习

    废话,写在前面 好久没写博客了,懒了,以后自觉写写博客,每周两三篇吧! 简单记录自己的学习经历,算是对自己的一点小小的督促! Java8的新特性很多,比如流处理在工作中看到很多的地方都在用,是时候扔掉 ...

  9. JAVA8新特性--集合流操作Stream

    原文链接:https://blog.csdn.net/bluuusea/article/details/79967039 Stream类全路径为:java.util.stream.Stream 对St ...

  10. JDK 8 新特性之函数式编程 → Stream API

    开心一刻 今天和朋友们去K歌,看着这群年轻人一个个唱的贼嗨,不禁感慨道:年轻真好啊! 想到自己年轻的时候,那也是拿着麦克风不放的人 现在的我没那激情了,只喜欢坐在角落里,默默的听着他们唱,就连旁边的妹 ...

随机推荐

  1. Orchard Core 使用工作流处理审批和创建内容项

    译自:http://www.ideliverable.com/blog/orchard-core-workflows-walkthrough-content-approval 转载请注明出处, 原文地 ...

  2. June 07th 2017 Week 23rd Wednesday

    Failure is the condiment that gives success its flavor. 失败是让成功变美味的调味料. There are kinds of flavors in ...

  3. table中设置tr行间距

    CSS border-collapse 属性设置表格的边框是否被合并为一个单一的边框 值 描述 separate 默认值.边框会被分开.不会忽略 border-spacing 和 empty-cell ...

  4. 【[USACO16OPEN]262144】

    发现这个数列的范围特别大但是值域的范围特别小 于是可以大胆猜测这道题值域肯定需要开到状态里去 又发现\(262144=2^{18}\)这个暗示非常明显啊,暗示这道题跟二进制有关系 其实也没什么关系 设 ...

  5. 课堂笔记:HTML----------图片热点

    HTML----------图片热点: 规划出图片上的一个区域,可以做出超链接,直接点击图片区域就可完成跳转的效果. 代码: <!DOCTYPE html PUBLIC "-//W3C ...

  6. CSS选择器种类及使用方法

    css选择器 有通配符选择器书写格式:*+{声名块} 并集选择器/组合选择器 书写格式;元素或类或id+""+元素或类或id+","+元素或类或id{声明块} ...

  7. 菜鸟笔记 -- Chapter 11 格式化

    我们在String中介绍过它有一个格式化的方法,在其它很多地方,也都能看到格式化的操作,那么这节我们就来认真了解一下Java中的格式化操作. 我们在操作中涉及到的格式化有字符串的格式化和一些其它数据类 ...

  8. Spring的声明式事务----Annotation注解方式(1)

    这里列一个小的demo工程,直接利用Spring的jdbcTemplate访问Mysql数据库. 工程结构: 数据库中的tbl_student表结构如下: 数据实体类Student.java代码如下: ...

  9. 关于 'list' object has no attribute 'select'

    我是在写爬虫是遇到了这个问题: c = chapter.select('href')AttributeError: 'list' object has no attribute 'select' 这是 ...

  10. <逆向学习第二天>如何手动脱UPX、Aspack壳

    UPS.AsPack压缩壳介绍: UPX .AsPack是一款先进的可执行程序文件压缩器.压缩过的可执行文件体积缩小50%-70% ,这样减少了磁盘占用空间.网络上传下载的时间和其它分布以及存储费用. ...