java 8-stream 常见使用

一、java8 新特性

java8 和java7 相比迎来了许多新特性,包括stream流、函数式编程、lambda表达式等等,在实际的工作中存在大量的stream流使用场景,因此用本文来记录一下在工作中常见的stream流的使用。

二、 stream 流简介

java8 stream流不同于传统的InputStream和OutPutStream。它专注于对集合对象进行各种便利、高效的聚合操作或大批量数据操作。stream结合lambda表达式以提高程序效率和可读性,提供串行、并行两种模式进行数据汇聚操作,其中并发模式为开发者省略了复杂的并发编码流程,让用户可以很方便的写出高性能的并发程序。摘自 《java8中的stream API详解》

三、stream常见方法

为啥要使用stream?很大的原因是它相较于传统的for循环具有更快的处理速度,更优雅的处理方式,更高效而又简单的并发编程支持.
很多时候想到stream流都是因为需要对一个集合中的元素做一系列操作,例如过滤特定元素、分类、取每个元素的某属性数据、求和、排序等等,简单来说就是实现一个filter-map-reduce的过程,产生一个最终结果或者一个副作用。

(一)、stream&Collection&Array&Map 转化

构造stream

// 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();

通过stream获取常见的集合类

// stream 转List:  collect(Collectors.toList())
stream.collect(Collectors.toList());
// stream 转Set:  collect(Collectors.toSet())
stream.collect(Collectors.toSet());
// stream 转Map:将Person的name属性作为key,将Person本身作为value,如果两个key重复了,使用新的key)
Person p1 = new Person("p1",23);
Person p2 = new Person("p2",21);
Person p3 = new Person("p3",25);
stream.collect(Collectors.toMap(Person::getName,Function.Identity,(c1,c2)->c2));
(二)、map/flatMap

map/flatMap实现了将输入元素映射成为输出元素

  • map:针对一个元素进行映射
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
List<Integer> squareNums = nums.stream().map(n -> n * n).collect(Collectors.toList());
  • flatMap:针对1对多关系将一个元素映射为多个元素
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
List<Integer> squareNums = nums.stream().
map(n -> n * n).
collect(Collectors.toList());
(三)、filter

filter实现对stream中的元素的过滤,不满足判断条件的元素将会被过滤,最终得到一个新的stream

 List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(3);
        list.add(4);
        list.add(14);
        list.add(56);
        list.add(12);
// 过滤大于3的所有元素,得到一个新的结果
        List<Integer> filterResult = list.stream().filter(num -> num > 3).collect(Collectors.toList());
(四)、forEach

stream流的forEach操作和普通的javafor循环在效率上并没有区别,唯一的区别在于stream流接收了一个lambada表达式,它是函数式编程和java语言结合的一个产物。
notice:

  • 使用forEach时不能对集合内的数据进行修改,否则会抛出ConcurrentModificationException 异常。不能使用return或者
  • forEach结束之后,stream流将会被终止,不能再被执行stream的其他操作
(五)、FindFirst

当需要从stream流中拿到第一个数据的时候,findFirst会为你提供一个安全有效的方式:Optional

// persons中拿到最小年龄的对象 ,若persons为空,则返回一个空的person    
persons.stream().sorted(Comparator.comparing(Person::getAge)).findFirst().orElse(new Person());
  • findFirst 返回stream流中的第一个对象的Optional容器(Optional可以优雅的对空对象的处理)
  • Optional提供的orElse方法会在Option包装的对象为空时提供一个默认的对象。
(六)、max/min/distinct/sorted

如果希望对stream中的数据取最大最小值、去重、按照自然数排序等操作可以直接调用上述的方法

// 获取optional类型的最大最小值(可能list为空,因此返回optional类型,避免直接)
Optional<Integer> max = list.stream().max(Comparator.comparing(Integer::intValue));
     Optional<Integer> min = list.stream().min(Comparator.comparing(Integer::intValue));
// 通过distinct去重,另一种方式是直接获取一个Set:········list.stream.collect(Collectors.toSet());
	List<Integer> distinctList = 			list.stream().distinct().collect(Collectors.toList());
// 使用sorted实现排序,最佳效率为O(NlogN)
List<Integer> sorted = list.stream().sorted().collect(Collectors.toList());
(七)、match

使用3种match方法实现对stream流中的数据进行快速的过滤,只要有一个数据不满足就直接退出,返回false

  • allMatch:Stream 中全部元素符合传入的 predicate,返回 true
  • anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
  • noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true

上一篇:JDK1.8新特性(二):Collectors收集器类


下一篇:设置椭圆形的CSS时,高度的设置是宽度的多少