web-dev-qa-db-ja.com

メソッドシグネチャのスローとJavaのスローステートメントの違い

メソッドシグネチャのスローとJavaのスローステートメントの違いを明確にしようとしています。メソッドシグネチャのスローは次のとおりです。

public void aMethod() throws IOException{
    FileReader f = new FileReader("notExist.txt");
}

スローステートメントは次のとおりです。

public void bMethod() {
    throw new IOException();
}

私の理解では、メソッドシグネチャのthrowsは、メソッドがそのような例外をスローする可能性があるという通知です。 throwステートメントは、状況に応じて作成されたオブジェクトを実際にスローするものです。その意味で、メソッドにthrowステートメントが存在する場合、メソッドシグネチャのthrowsは常に表示されます。

ただし、次のコードはそうではないようです。コードはライブラリからのものです。私の質問は、なぜそれが起こっているのですか?概念を間違って理解していますか?

このコードは、Java.util.linkedListのコピーです。 @authorジョシュ・ブロッホ

 /**
 * Returns the first element in this list.
 *
 * @return the first element in this list
 * @throws NoSuchElementException if this list is empty
 */
public E getFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return f.item;
}

答えを更新:

更新1:上記のコードは次と同じですか?

// as far as I know, it is the same as without throws
public E getFirst() throws NoSuchElementException {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return f.item;
}

更新2:チェック例外の場合。署名に「スロー」が必要ですか?はい。

// has to throw checked exception otherwise compile error
public String abc() throws IOException{
    throw new IOException();
}
33
Weishi Zeng

あなたはほとんど正しいです。少しだけ言及することを除いて。

throwsは、名前とパラメーターと同じくらいメソッドAPIの一部です。クライアントは、そのメソッドを呼び出す場合、その例外を処理する必要があることを知っています-単にそれをスローするか、それをキャッチして処理することで(実際には、オリジナルをラップする別の例外をスローする必要があります)。 throwsはコンパイル時に処理されます。

throwは、悪いことをランタイムに知らせる実際の動作であり、私たちが心配していた例外的な状態が実際に起こったことです。そのため、実行時に処理する必要があります。

しかし、「メソッドにthrowステートメントが存在する場合、メソッドシグネチャのスローは常に表示されるはずです」と言ったとき、あなたはまったく正しくありませんでした。それはしばしば真実ですが、常にそうとは限りません。メソッド内で例外をスローする別のメソッドを呼び出すこともできます。キャッチできない場合は、メソッドでスローする必要があります。その場合、私が同じ例外を明示的にスローすることはありません。

最後のポイントは、例外がchecked例外の場合、throwsで例外を宣言するだけですRuntimeExceptionからの例外クラス階層の反対側から。一般的なチェック例外はIOExceptionとSQLExceptionです。チェック例外は、自分で処理しない場合、メソッドシグネチャのthrows部分にリストする必要があります。 RuntimeExceptionをサブクラス化するもの(例のNoSuchElementExceptionや、嫌われているNullPointerExceptionなど)は、チェックされない例外であり、キャッチしたりスローしたりする必要はありません。

通常、回復可能な問題(クライアントが発生する可能性があることを知っており、問題を適切に処理して続行できる)にはチェック例外を使用し、壊滅的な問題(データベースに接続できないなど)には未チェック例外を使用します。

すべてのAOPを通り抜けることができる場合、 this は、チェック済みおよび未チェックの例外を効果的に使用する方法についての素晴らしい議論です。

29
Vidya

Vidyaはあなたの質問に素晴らしい答えを提供してくれました。

最も重要な言葉は「最後のポイントは、例外がチェックされた例外である場合に例外をスローで宣言するだけです」

サンプルコードを表示するだけで、これはどういう意味ですか。何らかのデータを渡すためにFileOutputStreamを使用したいと想像してください。関数は次のようになります。

public void saveSomeData() throws IOException {
  FileInputStream in = null;
  FileOutputStream out = null;

  try {
    in = new FileInputStream("input.txt");
    out = new FileOutputStream("output.txt");
    int c;

    while ((c = out.read() != -1) {
      in.write(c);
    }
  } catch (Exception e) {
    e.printStackTrace();
  } finally {
    // Close in
    if (in != null) {
      in.close(); // <-- If something bad happens here it will cause runtime error!
    }
    // Close out
    ...
  }
}

ここで、スローIOExceptionを指定せず、finally {}ステートメント内で何か悪いことが発生すると、エラーが発生することを想像してください。

5
0leg

正しく推測したように、メソッドシグネチャのthrow属性は、呼び出し側がキャッチする必要がある例外をメソッドが発生させるというコンパイラーへのヒントです。この種類の例外、つまりchecked exceptionと呼ばれるものは、呼び出し元[〜#〜] must [〜#〜]呼び出し元に常にキャッチまたはディスパッチします。これはコンパイラレベルの何かであり、シグネチャはメソッドがスローできる例外を指定します。これにより、try-catchまたは呼び出し側での再ディスパッチとメソッド内のどこかのthrowステートメントは、開発者がメソッドの動作について何かを指定するために置く制約です。

一方、他の例外、つまりuncheckedまたはruntime exceptions、( NoSucheElementExceptionは1つの例です)は、さまざまな状況から発生するため、指定を強制されない例外です。

概念上の違いは、通常、チェック例外は開発者が何らかの形で処理する必要がある例外的な状況(IOExceptionについて考える)を警告するために使用され、チェックされない例外は実際のエラー(NullPointerExceptionあなたの例NoSuchElementException

3
Jack

RuntimeExceptionsはtry-catchブロックで処理する必要がないため、スローされると宣言する必要はありません。 NoSuchElementExceptionRuntimeExceptionです。

2
Pshemo