博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java8 新特性之Stream API
阅读量:6617 次
发布时间:2019-06-25

本文共 6992 字,大约阅读时间需要 23 分钟。

1. Stream 概述

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

1.1 什么是 Stream

  1. Stream(流)是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列;
    "集合讲的是数据,流讲的是计算!"
  2. 注意:
    • Stream 自己不会存储元素;
    • Stream 不会改变源对象; 相反,它们会返回一个持有结果的新Stream;
    • Stream 操作是延迟执行的; 这意味着它们会等到需要结果的时候,才执行;

1.2 Stream 操作的三个步骤

  1. 创建 Stream
    • 一个数据源(如: 集合,数组),获取一个流;
  2. 中间操作
    • 一个中间操作链,对数据源的数据进行处理;
  3. 终止操作(终端操作)
    • 一个终止操作,执行中间操作链,并产生结果;
// 测试类public class TestStreamAPI{    // 创建 Stream    @Test    public void test(){        // 1. 可以通过 Collection 集合提供的 stream() 或 parallelStream()        List
list = new ArrayList<>(); Stream
stream = list.stream(); // 2. 可以通过 Arrays 中的静态方法 stream() 获取数组流 Employee[] emps = new Employee[10]; Stream
stream2 = Arrays.stream(emps); // 3. 通过 Stream 类中的静态方法 of() Stream
stream3 = Stream.of("aa","bb","cc"); // 4. 创建无限流 // 迭代 Stream
stream4 = Stream.iterate(0,(x) -> x+2); // 生成 Stream.generate(() -> Math.random()) .limit(5) .forEach(System.out::println); } // 中间操作 // 多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则,中间操作不会执行任何的处理! // 而在终止操作时,一次性全部处理,称为"惰性求值" // 中间操作包括: 筛选与切片, 映射, 排序, /* * 筛选与切片 * filter(): 接收 Lambda, 从流中排除某些元素; * limit(): 截断流,使其元素不超过给定数量; * skip(n): 跳过元素,返回一个扔掉了前 n 个元素的流; 若流中元素不足n个,返回一个空流;与 limit(n) 互补; * distinct(): 筛选,通过流所生成元素的 hashCode() 和 equals() 取出重复元素 */ List
employees = Arrays.asList( new Employee("张三",16,1000), new Employee("李四",22,2000), new Employee("熊大",25,1300), new Employee("熊二",32,1200), new Employee("赵六",43,3200) ); @Test public void test2(){ // 筛选与切片 // 中间操作: 不会执行任何操作 Stream
stream = employees.stream() .filter((e) -> e.getAge() > 26); // 终止操作: 一次性执行全部内容,即"惰性求值" stream.forEach(System.out:println); } /* * 映射 * map(): 接收 Lambda, 将元素转换成其他形式或提取信息,接受一个函数作为参数; 该函数会被应用到每个 * 元素上,并将其映射成一个新的元素; * flatMap(): 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流; */ @Test public void test3(){ List
list = Arrays.asList("aaa","bbb","ccc","ddd"); // 将 list 集合中的元素转换成大写 list.stream() .map((str) -> str.toUpperCase()) .forEach(System.out::println); // 获取employees中的姓名 employees.stream() .map(Employee::getName) .forEach(System.out::println); // flatMap() 使用之前: Stream
> stream = list.stream() .map(TestStreamAPI::filterCharscter); stream.forEach((sm) ->{ sm.forEach(System.out::println); }); // flatMap() list.stream() .flatMap(TestStreamAPI::filterCharacter) .forEach(System.out::println); } public static Stream
filterCharacter(String str){ List
list = new ArrayList<>(); for(Character ch : str.toCharArray()){ list.add(ch); } return list.stream(); } /* * 排序 * sorted(): 自然排序(Comparable) * sorted(Comparator com): 定制排序 (Comparator) */ List
list = Arrays.asList("bbb","zzz","yyy","ccc","sss"); list.stream() .sorted() .forEach(System.out::println); // 员工排序 employees.stream() .sorted((e1,e2) -> { if(e1.getAge().equals(e2.getAge())){ return e1.getName().compareTo(e2.getNme()); }else{ return e1.getAge().compareTo(e2.getAge()); } }).forEach(System.out::println); // 终止操作(终端操作) // 终止操作包括: 查找和匹配, 归约, 收集 /* * 查找和匹配 * allMatch: 检查是否匹配所有元素 * anyMatch: 检查是否至少匹配一个元素 * noneMatch: 检查是否都不匹配 * findFirst: 返回第一个元素 * findAny: 返回当前流中的任意元素 * count: 返回流中元素的总个数 * max: 返回流中最大值 * min: 返回流中最小值 */ List
employees = Arrays.asList( new Employee("张三",16,1000,Status.FREE), new Employee("李四",22,2000,Status.BUSY), new Employee("熊大",25,1300,Status.VACATION), new Employee("熊二",32,1200,Status.FREE), new Employee("赵六",43,3200,Stutus.BUSY) ); // 备注: 其中Status为枚举类型,共有:FREE(空闲),BUSY(忙碌),VACATION(休假)三种状态 boolean b1 = employees.stream() .allMatch((e) -> e.getStatus().equals(Status.BUSY)); System.out.println(b1); // 首先,按照工资排序,然后,获取第一个员工 Optional
op = employees.stream() .sorted((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary())) .findFirst(); System.out.println(op.get()); /* * 归约 * reduce(T identity, BinaryOperator) / reduce(BinaryOperator) * 可以将流中元素反复结合起来,得到一个值; 其中 第一个参数identity,表示起始值 */ // 需求: 将list集合中的元素相加 List
list = Arrays.asList(1,2,3,4,5,6,7,8,9,10); Integer sum = list.stream() .reduce(0,(x,y) -> x+y); System.out.println(sum); // 获取员工工资的总和 Optional
op = employees.stream() .map(Employee::getSalary) .reduce(Double::sum); System.out.println(op.get()); /* * 收集 * collect: 将流转换为其他形式,接收一个Collector 接口的实现,用于给 Stream 中元素做汇总的方法 * Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List, Set, Map) * Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例; */ // 需求: 将员工中的名字收集到 list 集合 List
list = employees.stream() .map(Employee:getName) .collect(Collectors.toList()); list.forEach(System.out::println); // 将员工姓名收集到 HashSet 中 HashSet
hset = employees.stream() .map(Employee::getName) .collect(Collectors.toCollection(HashSet::new)); // 员工总人数 Long count = employees.stream() .collect(Colletors.counting()); System.out.println(count); // 工资平均值 Double avg = employees.stream() .collect(Collectors.averagingDouble(Employee::getSalary)); System.out.println(avg); // 工资总和 Double sum = employees.stream() .collect(Collectors.summingDouble(Employee::getSalary)); System.out.println(sum); // 按照Status进行分组 Map
> map = employees.stream() .collect(Collectors.groupingBy(Employee::getStatus)); System.out.println(map); // 分区(满足条件的一个区,不满足条件的在另一个区) Map
> map = employees.stream() .collect(Collectors.partitioningBy((e) -> e.getSalary() > 1700)); System.out.println(map); DoubleSummaryStatistics dss = employees.stream() .collect(Collectors.summarizingDouble(Employee::getSalary)); System.out.println(dss.getSum()); System.out.println(dss.getAverage()); System.out.println(dss.getMax()); // 连接字符串 String str = employees.stream() .map(Employee::getName) .collect(Collectors.joining(",")); System.out.println(str);}

2. 并行流

  • 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流;
  • Java8 中将并行进行了优化,我们可以很容易的对数据进行并行操作;Stream API 可以声明性地通过parallel()
    sequential()在并行流与顺序流之间进行切换;
  • Fork/Join 框架: 就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将
    一个个的小任务运算的结果进行 join 汇总;

1222878-20171110170132638-1216886325.png

// java8 并行流//      并行流底层依赖 Fork/Join 框架// 需求: 计算1000亿的和public class TestForkJoin{    @Test    public void test(){        LongStream.rangeClosed(0,100000000000L)                  .parallel()                  .reduce(0, Long::sum);    }}

3. Optional 类

  1. Optional<T>类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用null表示一个值不存
    在,现在Optional可以更好的表达这个概念,而且可以避免空指针异常;
  2. 常用方法:
    • Optional.of(T t): 创建一个 Optional 实例;
    • Optional.empty(): 创建一个空的 Optional 实例;
    • Optional.ofNullable(T t): 若 t 不为null,创建 Optional 实例; 否则,创建空实例;
    • isPresent(): 判断是否包含值;
    • orElse(T t): 如果调用对象包含值,返回该值,否则,返回t;
    • orElseGet(Supplier s): 如果调用对象包含值,返回该值; 否则,返回 s 获取的值;
    • map(Function f): 如果有值,就对其处理,并返回处理后的Optional; 否则,返回Optional.empty();
    • flatMap(Function mapper): 与map类似,要求返回值必须是Optional;
// 测试类public class TestOptional{    @Test    public void test(){        Optional
op = Optional.of(new Employee("张三",13,2000)); Employee emp = op.get(); System.out.println(emp); }}

参考资料

转载于:https://www.cnblogs.com/linkworld/p/7814920.html

你可能感兴趣的文章
python list unicode转中文显示
查看>>
我的友情链接
查看>>
percona tools 之 pt-query-digest
查看>>
Centos7没有安装ifconfig命令的解决方法
查看>>
我的友情链接
查看>>
linux命令备忘 ulimit 常见服务的启动
查看>>
浅谈参数innodb_undo_tablespaces
查看>>
PHP加载MSSQL失败的解决办法
查看>>
MySQL系列之B-2------MySQL安装
查看>>
普通用户启动redis
查看>>
Memcached实现Session共享
查看>>
1.4-shell自定义变量
查看>>
ansible模块使用
查看>>
grep之正则表达式用法
查看>>
Oracle查询所有序列
查看>>
OGG运维优化脚本(十三)-信息同步类--进程信息上传
查看>>
详解Linux下挂载和格式化虚拟磁盘
查看>>
用永中Office过把DJ瘾
查看>>
SSL/TLS协议簇加解密流程
查看>>
我的友情链接
查看>>