集合优化了对象的存储,而流(Streams)则是关于一组组对象的处理。

What

  • 声明式编程(Declarative programming)

是一种编程风格——它声明了要做什么,而不是指明(每一步)如何做。相较于命令式编程(Imperative programming)的形式(指明每一步如何做)会更易理解。函数式编程和流式编程都属于声明式编程。

  • 流的优势
  1. 流可以在不曾使用赋值或可变数据的情况下,对有状态的系统建模,这非常有用。(简单理解就是在解决同样问题时,流可以减少变量的数量,即降低问题的复杂度);
  2. 流使用内部迭代,产生的代码可读性更强。而且能更简单的使用多核处理器,通过放弃对迭代过程的控制,可以把控制权交给并行化机制;
  3. 流是懒加载的。这代表着它只在绝对必要时才计算。你可以将流看作“延迟列表”。由于计算延迟,流使我们能够表示非常大(甚至无限)的序列,而不需要考虑内存问题。
  • 说明
  1. Stream自己不会存储元素;
  2. Stream 不会改变源对象,相反,它们会返回一个持有结果的新Stream;
  3. Stream 是懒加载的。
  • Optional类

主要用于防止空指针异常,在Stream使用归约等操作后会返回Optional对象。
常用方法如下:

创建Optional类对象的方法
Optional.of(T t) 创建一个Optional实例,t必须为非空
Optional.empty() 创建一个空的Optional实例
Optional.ofNullable(T t) t可以为null
判断Optional容器中是否包含对象
boolean isPresent() 判断是否包含对象
void ifPresent(Consumer c) 如果有值就将其作为参数传递给Consumer接口实例执行
获取Optional容器的对象
T get() 返回被包装对象,无则抛异常
T orElse(T other) 返回被包装对象,无则返回指定的other对象
T orElseGet(Supplier other) 返回被包装对象,无则返回Supplier实例对象
T orElseThrow(Supplier e) 返回被包装对象,无则抛出Supplier实例提供的异常

How

流(steam)由 创建 —> 中间操作 —>终止操作 这三部分组成 细节如下:

创建(source

  • 方式一:Stream自身的静态方法

通过Stream类中的静态方法of(…)

  1. public static<T> Stream<T> of(T... values) {
  2. return Arrays.stream(values);
  3. }
  • 方式二:通过集合

Collection接口提供的stream()或parallelStream()

  1. //串行流
  2. default Stream<E> stream() {
  3. return StreamSupport.stream(spliterator(), false);
  4. }
  5. //并行流
  6. default Stream<E> parallelStream() {
  7. return StreamSupport.stream(spliterator(), true);
  8. }
  • 方式三:通过数组

Arrays类的静态方法stream(…)

  1. public static <T> Stream<T> stream(T[] array) {
  2. return stream(array, 0, array.length);
  3. }
  • 方式四:创建无限流

    • 生成器创建无限流 Stream.generate

      1. public static<T> Stream<T> generate(Supplier<T> s) {
      2. Objects.requireNonNull(s);
      3. return StreamSupport.stream(
      4. new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
      5. }
    • 迭代器创建无限流 Stream.iterate

Stream.iterate() 产生的流的第一个元素是种子(iterate方法的第一个参数),然后将种子传递给方法(iterate方法的第二个参数)。方法运行的结果被添加到流(作为流的下一个元素),并被存储起来,作为下次调用 iterate()方法时的第一个参数,以此类推。

  1. public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
  2. Objects.requireNonNull(f);
  3. final Iterator<T> iterator = new Iterator<T>() {
  4. @SuppressWarnings("unchecked")
  5. T t = (T) Streams.NONE;
  6. @Override
  7. public boolean hasNext() {
  8. return true;
  9. }
  10. @Override
  11. public T next() {
  12. return t = (t == Streams.NONE) ? seed : f.apply(t);
  13. }
  14. };
  15. return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
  16. iterator,
  17. Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
  18. }

操作(intermedia)

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

  • 筛选与切片 | 方法 | 描述 | | —- | —- | | filter(Predicate p) | 接收Lambda,从流中过滤掉不符合的元素 | | distinct() | 筛选,通过流所生成元素的hashCode()和equals()去除重复元素 | | limit(long maxSize) | 截断流,返回流中前n个元素的流 | | skip(long n) | 返回一个去掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补 |

  • 映射 | 方法 | 描述 | | —- | —- | | map(Function f) | 接收一个函数型接口,该函数会被应用到每个元素上,并将其映射成为一个新的元素 | | flatMap(Function f) | 接收一个函数型接口,将流中的每个值都换成另一个流,然后把所有流连接成一个流 | | peek(Consumer c) | peek 操作 一般用于不想改变流中元素本身的类型或者只想元素的内部状态时 |

  • 排序 | 方法 | 描述 | | —- | —- | | sorted() | 产生一个新流,自然排序 | | sorted(Comparator c) | 产生一个新流,定制排序 |

终止(Terminal)

终端操作(Terminal Operations)将会获取流的最终结果,至此我们无法再继续往后传递流。因此,它总是我们在流管道中所做的最后一件事。

  • 查找与匹配 | 方法 | 描述 | | —- | —- | | allMatch(Predicate p) | 检查是否匹配所有元素 | | anyMatch(Predicate p) | 检查是否至少匹配一个元素 | | noneMatch(Predicate p) | 检查是否没有匹配所有元素 | | findFirst() | 返回第一个元素 | | findAny() | 返回当前流中的任意元素 | | count() | 返回流中元素个数 | | max(Comparator c) | 返回流中最大值 | | min(Comparator c) | 返回流中最小值 |
  • 归约

在大数据应用中常用map和reduce的连接,称为map-reduce模式,即,根据指定的计算模型将Stream中的值计算得到一个最终结果;

方法 描述
reduce(T identity, BinaryOperator b) 将流中元素反复结合起来,得到一个值T
reduce(BinaryOperator b) 将流中元素反复结合起来,得到一个值 Optional
  • 收集 | 方法 | 描述 | | —- | —- | | collect(Collector c) | 将流转换为其它形式。接收一个Collector接口的实现类,用于给Stream中元素做汇总的方法 |
  • Collector 接口中方法的实现决定了如何对流执行收集的操作(如 收集到List、Set、Map)。另外,Collectors实用类提供类很多静态方法,可方便地创建常见收集器实例,如下: | 方法 | 返回类型 | | —- | —- | | toList() | List | | toSet() | Set | | toCollection(…) | Collection | | Collectors.groupingBy(Function classifier) | |