为什么 Java 编译器允许重用 Stream?

Why does Java compiler allow to reuse a Stream?

让我们想象一下下面的代码:

Stream<Integer> numberStream = ...;

Predicate<Integer> isEven = ...;
Predicate<Integer> isOdd = ...;

List<Integer> evenNumbers = numberStream
    .filter(isEven)
    .collect(Collectors.toList());

List<Integer> oddNumbers = numberStream 
    .filter(isOdd)
    .collect(Collectors.toList()); // this line will throw IllegalStateException

以上代码编译时没有任何警告。但是,尝试 运行 将始终导致 IllegalStateException

查了一下,发现一个Stream只能有一个终端操作,所以基本上把它放在一个变量里是没有意义的。

在我看来,编译器很容易发现这个错误。为什么它编译没有错误?是否存在这样的代码有用的用例?

从某种意义上说,编译器很简单。

它根据 Java 语言的规则验证您的代码是否合法,并且您的所有调用是否符合 Java 语言规则和类型系统的要求。

无论是语言规则 还是类型系统 都以某种方式 "encodes" 无法重用 Stream。这只是编译器不知道的事实。

将流视为构建在 Java 之上的特定领域语言。编译器只知道该概念的较低 "Java" 层,但不了解较高级别 Streams 的规则 "language".

因此,虽然编译器 可以 可以想象地被告知该特定语言的规则,但这是一条危险的道路,因为有很多很多领域特定语言都像这样哪一个可能想要验证并正确地完成它们是......不太可能。