1. 概要

この簡単な記事では、Java8でStreamクラスを操作するときに発生する可能性のある一般的な例外について説明します。

IllegalStateException: stream has already been operated upon or closed.

この例外が発生したときのシナリオと、それを回避するための可能な方法を、実際の例とともに説明します。

2. 原因

Java 8では、各 Stream クラスは、データの使い捨てシーケンスを表し、複数のI/O操作をサポートします。

Stream は、一度だけ操作する必要があります(中間またはターミナルストリーム操作を呼び出す)。 Stream が再利用されていることを検出した場合、Stream実装はIllegalStateExceptionをスローする可能性があります。

Stream オブジェクトで端末操作が呼び出されるたびに、インスタンスが消費されて閉じられます。

したがって、は、 Streamを消費する単一の操作のみを実行できます。それ以外の場合は、Streamがすでに実行していることを示す例外が発生します。操作されたか、閉じられました。

これを実際の例に変換する方法を見てみましょう。

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

結果として:

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

#findAny()メソッドが呼び出された後、 stringStream が閉じられるため、 Stream でそれ以上の操作を行うと、IllegalStateExceptionがスローされます。 ]、そしてそれは #findFirst()メソッドを呼び出した後に起こったことです。

3. ソリューション

簡単に言うと、ソリューションは、必要になるたびに新しいStreamを作成することで構成されます。

もちろん、手動で行うこともできますが、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());

結果として:

A
A

定義しました streamSupplier タイプのオブジェクトストリーム 、これはまったく同じタイプです #得る() メソッドが戻ります。 Supplier は、入力を受け取らず、新しいStreamを返すラムダ式に基づいています。

サプライヤーで機能メソッドget()を呼び出すと、新しく作成された Stream オブジェクトが返され、別のStream操作を安全に実行できます。 。

5. 結論

このクイックチュートリアルでは、 Streamがすでに閉じているか、操作されています。

この記事の完全なソースコードとすべてのコードスニペットは、GitHubにあります。