通过供应商<stream <t>&gt;时Stream.generate方法的行为争论

时间:2018-01-05 20:24:08

标签: java lambda parameters java-8 java-stream

在阅读this questionone of its answers之后,我决定自己进行一些测试。令我惊讶的是,我遇到了一个看起来很奇怪的情况。

以下是代码:

public class InfiniteRepeatingStream {

    public static void main(String[] args) {

        Stream<Integer> s1 = repeatFromSupplier(() -> Stream.of(1, 2, 3));
        s1.sequential().limit(10).forEachOrdered(System.out::print);

        System.out.print("\n----------------\n");

        Stream<Integer> s2 = repeatFromStream(Stream.of(1, 2, 3));
        s2.sequential().limit(10).forEachOrdered(System.out::print);
    }

    static <T> Stream<T> repeatFromSupplier(Supplier<Stream<T>> supplier) {
        return Stream.generate(supplier).flatMap(s -> s);
    }

    static <T> Stream<T> repeatFromStream(Stream<T> stream) {
        return Stream.generate(() -> stream).flatMap(s -> s);
    }
}

如您所见,repeatFromSupplierrepeatFromStream方法之间的区别在于它的参数以及传递给Stream.generate方法的内容。

虽然repeatFromSupplier方法接收类型为Supplier<Stream<T>>的参数并将此参数直接传递给Stream.generate方法,但repeatFromStream方法接收类型为{{1}的参数并通过Stream<T>内联lambda表达式创建Supplier<Stream<T>>,该表达式立即传递给() -> stream方法。

我希望这两种方法都表现出相同的行为,因为我认为差异只是美化。

但是,此代码显示Stream.generaterepeatFromSupplier方法的不同行为。如果您运行它,您会注意到repeatFromStream方法按预期工作(它打印repeatFromSupplier),而1231231231方法打印repeatFromStream并抛出{ {1}}。

现在,我知道为什么以及何时抛出此异常。我不是在询问它。相反,我想知道为什么两种方法的行为都不同。

1 个答案:

答案 0 :(得分:4)

s1的名义情况下,您每次都会致电供应商创建新流:

() -> Stream.of(1, 2, 3)

但是在s2的情况下,您创建一个流,然后始终从供应商返回相同的实例:

() -> stream

这与此代码基本相同:

Stream<Integer> s = Stream.of(1, 2, 3); // now Stream.of is only executed once
Stream<Integer> s1 = repeatFromSupplier(() -> s);
s1.sequential().limit(10).forEachOrdered(System.out::print);

这也引发了异常。