Java 8ストリームに、チェックされた例外をスローする可能性のあるラムダを適用しようとするとします。
Stream<String> stream = Stream.of("1", "2", "3");
Writer writer = new FileWriter("example.txt");
stream.forEach(s -> writer.append(s)); // Unhandled exception: Java.io.IOException
これはコンパイルされません。
回避策の1つは、チェックされた例外をRuntimeException
にネストすることですが、後の例外処理が複雑になり、醜いだけです。
stream.forEach(s -> {
try {
writer.append(s);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
別の回避策としては、 制限付き 機能forEach
を プレーンな古いforeachループ に変換することです。
しかし、素朴なアプローチは失敗します:
for (String s : stream) { // for-each not applicable to expression type 'Java.util.stream.Stream<Java.lang.String>'
writer.append(s);
}
for (String s : stream.iterator()) { // foreach not applicable to type 'Java.util.Iterator<Java.lang.String>'
writer.append(s);
}
更新
この質問に答えるトリックが以前に投稿されました Stream <T>がIterable <T>を実装していないのはなぜですか として サイドアンサー は、その質問自体には実際には回答しません。彼らは異なることを尋ねるので、これはこの質問をその質問の複製として限定するには十分ではないと思います。
定義により foreachループには Iterable を渡す必要があります。
匿名クラスで実現できます:
for (String s : new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return stream.iterator();
}
}) {
writer.append(s);
}
Iterable
は 機能インターフェイス であるため、これは lambda で簡略化できます。
for (String s : (Iterable<String>) () -> stream.iterator()) {
writer.append(s);
}
これは メソッド参照 に変換できます:
for (String s : (Iterable<String>) stream::iterator) {
writer.append(s);
}
明示的なキャストは、中間変数またはメソッドparamで回避できます。
Iterable<String> iterable = stream::iterator;
for (String s : iterable) {
writer.append(s);
}
また、Maven Centralには StreamEx ライブラリがあり、反復可能なストリームやその他の特典をすぐに利用できます。
ここでは、ラムダとストリーム内でのチェック済み例外処理の回避策を提供するいくつかの最も人気のある質問とアプローチを示します。
Java 8:Lambda-Streams、例外付きのメソッドでフィルター
チェックされた例外を内部からスローする方法Java 8ストリーム?(チェックされていない例外にラップしない)
Java 8:ラムダ式での必須チェック例外処理。なぜ必須であり、オプションではないのですか?
Kotlin ;)
I 拡張を書き込んだ ストリームAPIにチェックされた例外をスローできるようにします。
Stream<String> stream = Stream.of("1", "2", "3");
Writer writer = new FileWriter("example.txt");
ThrowingStream.of(stream, IOException.class).forEach(writer::append);
次のようにすることもできます:
Path inputPath = Paths.get("...");
Stream<Path> stream = Files.list(inputPath);
for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext(); )
{
Path path = iterator.next();
// ...
}
ストリームはIterableを実装しておらず、配列でもないため、拡張forループでの使用には適していません。 Iterableを実装しない理由は、使い捨てのデータ構造であるためです。 Iterable.iteratorが呼び出されるたびに、すべての要素をカバーする新しいIteratorが返されます。 Streamの反復子メソッドは、Streamの現在の状態を反映するだけです。これは事実上、ストリームの別の見方です。
拡張forループで使用するストリームをラップすることにより、Iterableを実装するクラスを作成できます。しかし、(上記のように)Iterableを実際に実装することはできないので、これは疑わしいアイデアです。