“Stream has already been operated upon or closed” Exception in Java – “流已经被操作或关闭”Java中的异常情况

最后修改: 2017年 9月 18日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this brief article, we’re going to discuss a common Exception that we may encounter when working with the Stream class in Java 8:

在这篇简短的文章中,我们将讨论在Java 8中使用Stream类时可能遇到的一个常见Exception

IllegalStateException: stream has already been operated upon or closed.

We’ll discover the scenarios when this exception occurs, and the possible ways of avoiding it, all along with practical examples.

我们将发现发生这种异常的情况,以及避免这种情况的可能方法,所有这些都有实际的例子。

2. The Cause

2.原因

In Java 8, each Stream class represents a single-use sequence of data and supports several I/O operations.

在Java 8中,每个Stream类代表一个一次性的数据序列,并支持若干I/O操作。

A Stream should be operated on (invoking an intermediate or terminal stream operation) only once. A Stream implementation may throw IllegalStateException if it detects that the Stream is being reused.

一个Stream应该只被操作一次(调用一个中间或终端流操作)。如果一个流的实现检测到Stream正在被重复使用,它可能会抛出IllegalStateException

Whenever a terminal operation is called on a Stream object, the instance gets consumed and closed.

每当对Stream对象调用终端操作时,该实例就会被消耗并关闭。

Therefore, we’re only allowed to perform a single operation that consumes a Stream, otherwise, we’ll get an exception that states that the Stream has already been operated upon or closed.

因此,我们只允许执行一个消耗Stream的操作,否则,我们将得到一个异常,说明Stream已经被操作或关闭。

Let’s see how this can be translated to a practical example:

让我们看看如何将其转化为一个实际的例子。

Stream<String> stringStream = Stream.of("A", "B", "C", "D");
Optional<String> result1 = stringStream.findAny(); 
System.out.println(result1.get()); 
Optional<String> result2 = stringStream.findFirst();

As a result:

结果是。

A
Exception in thread "main" java.lang.IllegalStateException: 
  stream has already been operated upon or closed

After the #findAny() method is invoked, the stringStream is closed, therefore, any further operation on the Stream will throw the IllegalStateException, and that’s what happened after invoking the #findFirst() method.

在调用#findAny()方法后,stringStream被关闭,因此,对Stream的任何进一步操作都会抛出IllegalStateException,这就是调用#findFirst()方法后发生的情况。

3. The Solution

3.解决方案

Simply put, the solution consists of creating a new Stream each time we need one.

简单地说,该解决方案包括在我们每次需要时创建一个新的Stream

We can, of course, do that manually, but that’s where the Supplier functional interface becomes really handy:

当然,我们可以手动操作,但这正是Supplier功能界面变得非常方便的地方。

Supplier<Stream<String>> streamSupplier 
  = () -> Stream.of("A", "B", "C", "D");
Optional<String> result1 = streamSupplier.get().findAny();
System.out.println(result1.get());
Optional<String> result2 = streamSupplier.get().findFirst();
System.out.println(result2.get());

As a result:

结果是。

A
A

We’ve defined the streamSupplier object with the type Stream<String>, which is exactly the same type which the #get() method returns. The Supplier is based on a lambda expression that takes no input and returns a new Stream.

我们定义了streamSupplier对象,其类型为Stream<String>,这与#get()方法返回的类型完全相同。这个Supplier是基于一个lambda表达式,它不接受任何输入,并返回一个新的Stream

Invoking the functional method get() on the Supplier returns a freshly created Stream object, on which we can safely perform another Stream operation.

Supplier上调用功能方法get()会返回一个新创建的Stream对象,我们可以安全地对其进行另一个Stream操作。

5. Conclusion

5.结论

In this quick tutorial, we’ve seen how to perform terminal operations on a Stream multiple times, while avoiding the famous IllegalStateException that is thrown when the Stream is already closed or operated upon.

在这个快速教程中,我们看到了如何在Stream上多次执行终端操作,同时避免了著名的IllegalStateException,因为当Stream已经被关闭或被操作时,会抛出这个问题。

You can find the complete source code and all code snippets for this article over on GitHub.

你可以在GitHub上找到本文的完整源代码和所有代码片段