2017-11-04 9 views
3

Java 8では、Stream(AutoCloseable)は再利用できません。一度使用または使用されると、ストリームは閉じられます。したがって、リソースを試して試して宣言するユーティリティは何ですか? try-と資源の文とtry-with-resourcesステートメントを使用してStreamを宣言するかどうかの違いは何ですか?

例:

public static void main(String[] args) throws IOException { 

    try (Stream<Path> entries 
      = Files.walk(Paths.get("."), 4, FileVisitOption.FOLLOW_LINKS)) { 
     entries.forEach(x -> System.out.println(x.toAbsolutePath()));// the entries stream will be automatically closed at this point 
     //.. 
     System.out.println("Still in the Try Block"); 
    } //The entries will be closed again because it is declared in the try-with-resources statement 
} 

そして、ここでのtry catchブロック

public static void main(String[] args) throws IOException { 
     Stream<Path> entries = Files.walk(Paths.get("."), 4, FileVisitOption.FOLLOW_LINKS); 
     entries.forEach(x -> System.out.println(x.toAbsolutePath()));// the entries stream will be automatically closed at this point 
     System.out.println("Is there a risk of resources leak ?"); 
    } 

より安全なものですなしで同じ例?

ここ

新しいコード::私は、ストリームがクローズされたかどう確認するために私のコードを更新するいくつかの回答後

public static void main(String[] args) throws IOException { 

    resourceWithTry(); 
    resourceWithoutTry(); 
} 

private static void resourceWithTry() throws IOException { 
    try (Stream<Path> entries 
      = Files.walk(Paths.get("."), 4, FileVisitOption.FOLLOW_LINKS).onClose(() -> System.out.println("The Stream is closed"))) { 
     entries.forEach(x -> System.out.println(x.toAbsolutePath()));// the entries stream will be not automatically closed at this point 
     System.out.println("Still in the Try Block"); 
    } //The entries will be closed again because it is declared in the try-with-resources statement 
} 

private static void resourceWithoutTry() throws IOException { 
    Stream<Path> entries 
      = Files.walk(Paths.get("."), 4, FileVisitOption.FOLLOW_LINKS).onClose(() -> System.out.println("Without Try: The Stream is closed")); 
    entries.forEach(x -> System.out.println(x.toAbsolutePath()));// the entries stream will be not automatically closed at this point 
    System.out.println("Still in the Try Block"); 
} 

答えて

8

Java 8では、Stream(AutoCloseable)は再利用できません。一度 が消費または使用されると、ストリームは閉じられます。

正確ではありません。
StreamforEach()のような端末操作はストリームを閉じません。
ストリームパイプラインがもう消耗しないようにします。
どちらが違うのですか?

Package java.util.stream description状態:

端末操作が行われた後、ストリーム・パイプラインは 消費とみなされ、もはや使用することができます。 に同じデータソースを再度トラバースする必要がある場合は、データ のデータに戻って新しいストリームを取得する必要があります。

ストリームが閉じているとは限りません。次のコードで

ので
StreamインスタンスのAutoCloseable.close()メソッドが呼び出されることはありません:

Stream<Path> entries = Files.walk(Paths.get("."), 4, FileVisitOption.FOLLOW_LINKS); 
entries.forEach(x -> System.out.println(x.toAbsolutePath())); 

だからそれは常にストリームを閉じるために必要ですか? (明示的なclose()呼び出しまたはより良いtry-with-resourcesで)

java.util.stream.Stream<T>のjavadocは、ほぼすべてのStreamのインスタンスが使用した後AutoCloseable.close()で閉鎖する必要がないことを説明しています。
これはIOストリームの場合にのみ当てはまります。

ストリームはclose()メソッドを持ち、AutoCloseableを実装していますが、ほとんどのストリームインスタンスは使用後に実際に閉じる必要はありません。 一般に、ソースがIOチャネルであるストリーム(Files.lines(Path、Charset)によって返された など)のみがクローズする必要があります。ほとんどの ストリームは、特別なリソース管理を必要としない、コレクション、配列、または生成関数 によってサポートされています。我々のケースで

、あなたがFile Sを操作する(ストリームは、それが のtry-と資源文のリソースとして宣言することができます。閉じ 必要がない場合)ので、チャネルを閉じるために理にかなっています。
try-with-resourcesを使用すると、発生する可能性のあるリソースの枯渇の例外やエラーを回避できます。
処理中にエラーまたは例外が発生した場合、リソースはすべて同じリリースされている可能性があります。

+0

私の投稿を更新しました。ストリームが閉じられているかどうかを確認するための新しいコードを追加しました。ありがとうございました – Aguid

+1

もっと正確には、両方のケース(IOストリームまたはコレクションストリーム)では、例のようにメソッド呼び出しのケースで、ストリームインスタンスは**メソッドの戻り後に**パージ**されます(実際にはGCアクション。メソッドの呼び出しは、スタックのリターン後に破棄されます)。また、メソッド中に例外がスローされたかどうかにかかわらず、スタック上のローカル変数はパージされます。 (1/2) – davidxxx

+1

これらの違いは、リソース(IO)を使用するストリームがファイルをロックしたり接続を維持したりするメソッドを呼び出すということです。この特定のケースでは、リソースの戻り値を操作するメソッドとして、これらのクローズ可能なリソースの潜在的なロックをすべて削除したことを確認します(2/2) – davidxxx

1

docsによると、はい、それが推奨されます(そしてより安全)try-with-resourcesを使用してこのインスタンスで返されたストリームを閉じます。

ファイルシステムのリソースをタイムリーに廃棄する必要がある場合は、 try-wit stream操作が 完了した後に ストリームのcloseメソッドが呼び出されるように、h-resources構造体を使用する必要があります。

他の場合、Streamが配列またはリストから供給される場合、それは違いがありません。

3

ストリーム処理が中断され、完全には消費されず、自動的に閉じられません。この例を考えてみましょう :

Stream<Integer> nums = Stream.of(1, 2, 3); 
nums.onClose(() -> System.out.println("close was called")); 
nums.forEach(x -> { if (x > 1) throw new IllegalStateException(); }); 

これは、途中でクラッシュします、とonCloseは呼び出されません。 ストリームは開いたままであり、手動で閉じる必要があります。

あなたはのtry-と資源を使用している場合は、それが何で、 あなたが観察できるよう、正しく閉じ取得しません:

try (Stream<Integer> nums = Stream.of(1, 2, 3)) { 
    nums.onClose(() -> System.out.println("close was called")); 
    nums.forEach(x -> { if (x > 1) throw new IllegalStateException(); }); 
} 

それは消費しないので、これは拷問例、 ですストリームが閉じられていなくても、 ガベージコレクタがクリーンアップする のリソースをすべて閉じる必要があります。

したがって、try-with-resourcesステートメントで宣言するユーティリティは何ですか?

これは、ストリームが何であっても閉じられることを保証します。 ストリームが閉じられなければならないリソースによってバックアップされていない場合、 は実際には問題になりません。

上記の例では 、ちょうど違いを実証することであったが、そのようなコードでは、トライして、リソース、コード内 ノイズだけを使用するには、不必要な妄想ですので、それは実際に試してみる-と資源のない方が良いでしょう。

+0

@Kayaman true、その点を明確にしました – janos

+0

ストリームが自動的に閉じられているかどうかを確認するために投稿を更新しました(resourceWithoutTry()メソッドを参照)。 – Aguid

+0

コンシューマが例外をスローするかどうかは関係ありません。 'forEach'はストリームを決して閉じることはありません。それに加えて、メソッドがストリームの内部状態を変更したと仮定するのではなく、ストリームメソッドの戻り値を常に使用する必要があります。または、戻り値を本質的に使用する連鎖を使用してください: 'Stream.of(1,2,3).onClose(() - > System.out.println(" close was called ")).forEach(x-> {/*スローする必要はありません* /}); // – Holger

関連する問題