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

为什么Java编译器允许重用流?,java,java-stream,illegalstateexception,Java,Java Stream,Illegalstateexception,让我们想象一下以下代码: Stream<Integer> numberStream = ...; Predicate<Integer> isEven = ...; Predicate<Integer> isOdd = ...; List<Integer> evenNumbers = numberStream .filter(isEven) .collect(Collectors.toList()); List<Integ

让我们想象一下以下代码:

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
streamnumberstream=。。。;
谓词isEven=。。。;
谓词isOdd=。。。;
列表编号=numberStream
.过滤器(isEven)
.collect(Collectors.toList());
列表编号=numberStream
.过滤器(isOdd)
.collect(Collectors.toList());//此行将抛出IllegalStateException
以上代码编译时没有任何警告。但是,尝试运行它将始终导致
非法状态异常

在研究它之后,我发现一个
只能有一个终端操作,因此基本上没有必要将它存储在变量中


在我看来,这将是一个非常容易被编译器发现的错误。为什么它编译时没有错误?有没有这样的代码有用的用例?

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

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

无论是语言规则还是类型系统都无法“编码”不能重用的
流。这只是编译器不知道的一个事实

将streams视为构建在Java之上的特定于领域的语言。编译器只知道该概念中较低的“Java”层,但不理解较高级别的流“语言”的规则


因此,虽然可以想象编译器会被告知特定语言的规则,但这是一条危险的道路,因为有很多领域特定的语言,人们可以想象,想要验证这些语言,并且把它们做好是。。。不太可能。

简短回答:流不能重用的事实没有(也不能)在Java类型系统中编码。编译器对流一无所知(除了所使用的类)。编译器会检查您编写的代码是否符合Java语言定义的规范。但它不会检查代码在应用意义上是否正确。我认为您正在为IDE或maven/gradle构建寻找java linter插件。声纳也可能是一种选择