12

オブジェクトのセットをファイルに書き込む方法をいじっています。Iterable.forEach() を使用した以下の実装がコンパイルされないのはなぜですか? Eclipse で、IOException が処理されていないというメッセージが表示されます。私は IOExceptions を処理しているように見えるので、これは特に紛らわしいです。

  public void write(Iterable<?> objects) {
    try (BufferedWriter bw = new BufferedWriter(
        new OutputStreamWriter(
            new FileOutputStream("out.txt"), "UTF-8"));) {

      objects.forEach((o) -> bw.write(o.toString())); //Unhandled exception type IOException

  } catch (IOException e) {
    //handle exception
  }
}

明らかに、以下は機能します。上記が機能しない理由とその修正方法に興味があります。

for (Object o : objects) { bw.write(o.toString()); }

ConsumerIterableのドキュメントを確認しましたが、どちらもこれを解決する方法を提案していないようです。

4

4 に答える 4

11

前駆体: Catch or Specify Requirement .

ラムダを匿名クラスとして書きましょう。

objects.forEach(new Consumer<Object>() {
    public void accept(Object o) {
        bw.write(o.toString());
    }
});

私たちはそれを処理していますか?そうではないことは明らかです。

ラムダ式を書くときは、メソッドの本体を宣言しています。throwsまた、ラムダの節を宣言することもできません。

唯一の「回避策」は、次のようなことです。

try (BufferedWriter bw = new BufferedWriter(
    new OutputStreamWriter(
        new FileOutputStream("out.txt"), "UTF-8"));) {

    objects.forEach((o) -> {
        try {
            bw.write(o.toString()));
        } catch(IOException kludgy) {
            throw new UncheckedIOException(kludgy);
        }
    });

} catch (UncheckedIOException kludgy) {
    IOException cause = kludgy.getCause();
    // handle exception
}

( も参照してくださいUncheckedIOException。)

Iterable.forEachその例のように例外をラップしてスローすることが保証されます。

アクションによってスローされた例外は、呼び出し元に中継されます。

ただし、チェックされた例外をスローするコンテキストでの使用を避けるforEachか、ラムダの本体で例外をキャッチして処理することをお勧めします。

于 2015-04-24T19:54:09.817 に答える
7

文字列をファイルに出力することだけに関心がある場合は、PrintStreamおそらく他のクラスPrintWriterの代わりにor を使用してください。Writerとの注目すべき機能はPrintStreamPrintWriterそれらの印刷操作が をスローしないことIOExceptionです。またtoString、オブジェクトを自動的に呼び出すため、非常に便利です。

public void write1(Iterable<?> objects) {
    try (PrintStream ps = new PrintStream("printout.txt", "UTF-8")) {
        objects.forEach(ps::println);
    } catch (IOException ioe) {
        // handle
    }
}

エラーが気になる場合は、 を呼び出すことができますがPrintStream.checkError、発生した可能性のあるエラーの詳細はわかりません。

forEachただし、許可されていないコンテキスト ( など) 内から例外をスローするメソッドを呼び出したい場合はどうすればよいかという一般的な問題は依然として残っています。これは、対処するのが煩わしいだけですが、それほどではありません。ただし、いくつかの設定が必要です。Consumerをスローするa を書きたいとしIOExceptionます。独自の機能インターフェースを宣言する必要があります。

interface IOConsumer<T> {
    void accept(T t) throws IOException;
}

IOConsumer次に、 を に変換する関数を書く必要がありますConsumer。これは、IOExceptionキャッチしたUncheckedIOExceptionものを、この目的のために作成された例外である に変換することによって行われます。

static <T> Consumer<T> wrap(IOConsumer<? super T> ioc) {
    return t -> {
        try {
            ioc.accept(t);
        } catch (IOException ioe) {
            throw new UncheckedIOException(ioe);
        }
    };
}

これらが整ったら、元の例を次のように書き直すことができます。

public void write2(Iterable<?> objects) {
    try (BufferedWriter bw = new BufferedWriter(
             new OutputStreamWriter(
                 new FileOutputStream("out.txt"), "UTF-8"))) {
        objects.forEach(wrap(o -> bw.write(o.toString())));
    } catch (IOException|UncheckedIOException e) {
        //handle exception
    }
}
于 2015-04-25T06:46:57.560 に答える
3

問題はaccept、インターフェイスのメソッドConsumerが例外をスローするように宣言されていないことです。したがって、ラムダでチェック例外をスローするメソッドを使用することはできません。

解決策は、代わりに for each ループを使用することです。

于 2015-04-24T19:50:08.100 に答える
1

通常、例外が発生した場合、データをファイルに書き込みません。これを念頭に置いて、own consumer which will wrap the checked exception into an unchecked exception. このようにして、コンパイル時エラーを回避できます。以下のコードを試してください

import java.io.*;
import java.util.*;
public class HelloWorld{

     public static void main(String []args){
        write(Arrays.asList(1,2,3));
     }

  public static void write(Iterable<?> objects) {
    try (BufferedWriter bw = new BufferedWriter(
        new OutputStreamWriter(
            new FileOutputStream("c:\\out.txt"), "UTF-8"))) {

      objects.forEach(o->myConsumerThrowsRuntimeException(bw,o.toString())); //Unhandled exception type IOException

  } catch (Exception e) {
    //handle exception
  } 
  }
  public static void myConsumerThrowsRuntimeException(Writer writer , String data){
      try{
          writer.write(data);
      }catch(IOException e){

          throw new RuntimeException("Cannot write Data error is "+e.getMessage());
      } 
  } 
}
于 2015-04-25T11:02:27.560 に答える