java 新增特性 2

Stream 加强

Stream 是 Java8 的新特性,我之前的博客对其进行了详细的介绍:Java8 新特性 - Stream API。Java9 开始对 Stream 新增了 4 个新方法。

2|**1**增加单个参数构造方法,可为 null

在 Java8,新建一个值为 null 的 Stream,会报错java.lang.NullPointerException错误。
示例代码:



Stream stream = Stream.of(null);[](javascript:void(0); "复制代码")


错误:



Exception in thread "main" java.lang.NullPointerException
    at java.util.Arrays.stream(Arrays.java:5004)
    at java.util.stream.Stream.of(Stream.java:1000)[](javascript:void(0); "复制代码")


错误分析:

查看 Stream.of() 源码



    @SafeVarargs
    @SuppressWarnings("varargs") // Creating a stream from an array is safe
    public static<T> Stream<T> of(T... values) {
       return Arrays.stream(values);
    }

    public static <T> Stream<T> stream(T[] array) {
       return stream(array, 0, array.length);
    }[](javascript:void(0); "复制代码")


可以看见传入 null 会被解析为时一个数组对象,会进一步访问它的长度信息,导致了 NullPointerException 异常。

在 Java11 中,新增了ofNullable方法,可以传入 null。因为无法推断类型,所以返回的值为Object,示例代码如下:



Stream stream = Stream.ofNullable(null);
stream.forEach(System.out::println);[](javascript:void(0); "复制代码")


从源码中可以看出,当传入的是一个 null 时,返回的是一个空的对象。



    public static<T> Stream<T> ofNullable(T t) {
        return t == null ? Stream.empty()
                         : StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
    }[](javascript:void(0); "复制代码")


2|**2**增加 takeWhile 和 dropWhile 方法

takeWhile

首先来看一段示例代码:



Stream<Integer> stream = Stream.of(3, 6, 9, 12, 15);
stream.takeWhile(n -> n % 2 != 0)
        .forEach(System.out::println);[](javascript:void(0); "复制代码")


第一次看这段代码,可能第一印象就是找出流中的奇数打印出来,但是实际输出为:

3

所以 takeWhile 方法在计算到n % 2 == 0的时候就终止了,takeWhile 方法的作用是:从流中一直获取判定器为真的元素,一旦遇到元素为假,就终止处理!

dropWhile

与上面 takeWhile 一样的代码:



Stream<Integer> stream = Stream.of(3, 6, 9, 12, 15);
stream.dropWhile(n -> n % 2 != 0)
        .forEach(System.out::println);[](javascript:void(0); "复制代码")


返回的结果为:

6
9
12
15

结果正好与 takeWhile 相反,dropWhile 方法的作用为:只要判定器为真,就一直丢弃元素,直到为假,取为假后的所有元素!
iterate 重载

流的迭代,主要用于创建流,在指定初值的情况下,经过处理,然后将处理过的值作为初值,不断迭代。所以 iterate 创建的是一个无限流。
示例代码:



Stream.iterate(1, t -> 2 * t + 1)
        .limit(10)
        .forEach(System.out::println);[](javascript:void(0); "复制代码")


无限流有一个问题,在数值溢出之后,会一直重复 -1 的值。Java11 进行了优化,以让你提供一个 Predicate (判断条件) 来指定什么时候结束迭代,进行有限的迭代,示例代码如下:



Stream.iterate(1, t -> t< 1000, t -> 2 * t + 1)
        .forEach(System.out::println);