20

「うまくいかない可能性のあるものと、うまくいかない可能性のあるものとの主な違いは、うまくいかない可能性があるものがうまくいかない場合、通常、それを修正したり修正したりすることが不可能であることが判明することです。」-ダグラス・アダムス

クラス FileItems があります。FileItems コンストラクターはファイルを受け取り、ファイルが存在しない場合は例外 (FileNotFoundException) をスローします。そのクラスの他のメソッドにもファイル操作が含まれるため、FileNotFoundException をスローする機能があります。より良い解決策を見つけたいと思います。他のプログラマーがこれらの非常にありそうもない FileNotFoundExceptions をすべて処理する必要がないソリューション。

問題の事実:

  1. ファイルが存在することが確認されましたが、このメソッドが呼び出される前にファイルが削除される可能性はほとんどありません。
  2. 1 が発生する確率は非常に異なり、回復できないため、未チェックの例外を定義することをお勧めします。
  3. ファイルはすでに存在することがわかっているため、他のプログラマーがコードを記述してチェック済みの FileNotFoundException をキャッチすることを強制するのは、面倒で役に立たないようです。プログラムはその時点で完全に失敗するはずです。たとえば、コンピューターが発火する可能性は常にありますが、他のプログラマーにそれをチェック例外として処理させるほど正気でない人はいません
  4. 私は時々この種の例外の問題に遭遇し、この問題が発生するたびにカスタムのチェックされていない例外を定義すること (私の古い解決策) は面倒で、コードが肥大化します。

コードは現在このようになっています

 public Iterator getFileItemsIterator() {
    try{
        Scanner sc = new Scanner(this.fileWhichIsKnowToExist);
        return new specialFileItemsIterator(sc);        
       } catch (FileNotFoundException e){ //can never happen} 

    return null;
 }

カスタムのチェックされていない FileNotFoundException を定義せずに、どうすればこれを改善できますか? checkedException を uncheckException にキャストする方法はありますか?

4

8 に答える 8

53

これに対処する通常のパターンは、例外連鎖です。FileNotFoundException を RuntimeException にラップするだけです。

catch(FileNotFoundException e) {
    throw new RuntimeException(e);
}

このパターンは、特定の状況 (自分の状況など) で例外が発生しない場合だけでなく、例外を実際に処理する手段や意図がない場合 (データベース リンクの障害など) にも適用されます。

編集: この似たようなアンチパターンに気をつけてください。

catch(FileNotFoundException e) {
    throw new RuntimeException(e.getMessage());
}

これを行うと、元のスタック トレース内のすべての重要な情報が破棄され、問題の追跡が困難になることがよくあります。

別の編集: Thorbjørn Ravn Andersen が彼の応答で正しく指摘しているように、例外をチェーンしている理由をコメントで、またはさらに良いことに、例外メッセージとして述べても害はありません。

catch(FileNotFoundException e) {
    throw new RuntimeException(
        "This should never happen, I know this file exists", e);
}
于 2009-06-25T19:46:17.293 に答える
12

RuntimException 内に入れ子にすることで、チェック済みの例外を未チェックの例外に変換できます。例外がスタックの上位にキャッチされ、printStackTrace() を使用して出力された場合、元の例外のスタックも表示されます。

try {
    // code...
}
catch (IOException e) {
    throw new RuntimeException(e);
}

これは良い解決策であり、これらの状況で使用することをためらってはなりません。

于 2009-06-25T19:45:28.747 に答える
11

フォームの使用を検討してください

throw new RuntimeException("This should never happen", e);

代わりは。これにより、コードを読むときだけでなく、奇妙なシナリオで例外がスローされる必要がある場合でも、メンテナーに意味を伝えることができます。

編集:これは、例外を想定していないメカニズムを介して例外を渡す良い方法でもあります。たとえば、「データベースからさらに行を取得する」イテレータがある場合、Iterator インターフェイスは FileNotFoundException などのスローを許可しないため、このようにラップできます。イテレータを使用するコードでは、runtimeexception をキャッチし、元の例外を getCause() で調べることができます。従来のコード パスを通過するときに非常に便利です。

于 2009-06-25T19:58:28.703 に答える
8

これが非常にありそうもないので、プログラムを終了する必要があるというあなたの立場である場合は、既存のランタイム例外を使用してください。

try {
  ....

} catch (FileNotFoundException e) {
    throw new RuntimeException(e);
}
于 2009-06-25T19:46:27.573 に答える
1

IOExceptionファイルからの読み取りまたは書き込みを含むコード内の任意の時点で、スーパークラスとより一般的な例外をスローした方がよいでしょう。

クラスのコンストラクターの実行時にファイルが存在する可能性がありますが、次のことを保証するものではありません。

  1. メソッドが呼び出されたときに存在します
  2. 書き込み可能/読み取り可能です
  3. 別のスレッドがそれにアクセスせず、どういうわけかストリームを台無しにします
  4. 処理の途中でリソースが消えない

java.io車輪を再発明する代わりに、使用しているJDK /クラスがそうするように強制する場合はいつでも、IOExceptionを再スローするだけです。

また、私はコンストラクターから例外をスローするクラスが嫌いです-私があなただったら、これらを取り除きます。

于 2009-06-25T19:47:08.943 に答える
1

少しグーグルで調べたところ、このコードの塊が見つかりました。私が考えるアプローチはもう少し柔軟です

この記事の賛辞

class SomeOtherException extends Exception {}

public class TurnOffChecking {
  private static Test monitor = new Test();
  public static void main(String[] args) {
    WrapCheckedException wce = new WrapCheckedException();
    // You can call f() without a try block, and let
    // RuntimeExceptions go out of the method:
    wce.throwRuntimeException(3);
    // Or you can choose to catch exceptions:
    for(int i = 0; i < 4; i++)
      try {
        if(i < 3)
          wce.throwRuntimeException(i);
        else
          throw new SomeOtherException();
      } catch(SomeOtherException e) {
          System.out.println("SomeOtherException: " + e);
      } catch(RuntimeException re) {
        try {
          throw re.getCause();
        } catch(FileNotFoundException e) {
          System.out.println(
            "FileNotFoundException: " + e);
        } catch(IOException e) {
          System.out.println("IOException: " + e);
        } catch(Throwable e) {
          System.out.println("Throwable: " + e);
        }
      }
    monitor.expect(new String[] {
      "FileNotFoundException: " +
      "java.io.FileNotFoundException",
      "IOException: java.io.IOException",
      "Throwable: java.lang.RuntimeException: Where am I?",
      "SomeOtherException: SomeOtherException"
    });
  }
} ///:~
于 2009-06-25T19:57:08.300 に答える
1

私は同じ問題を経験しました。

最も単純なケースでは、ユーザーにエラーを通知し、操作を繰り返すかキャンセルするよう提案します。

一般に、ワークフローは一連のアクション (I/O を含む) であり、各アクションは前のアクションが成功したと「仮定」します。

私が選んだアプローチは、「ロールバック」アクションのリストを作成することです。ワークフローが成功した場合、それらは無視されます。例外が発生した場合は、ロールバックを実行し、ユーザーに例外を提示します。

これ:

  • データの整合性を保つ
  • はるかに簡単にコーディングできます

典型的な機能は次のようなものです:

returntype func(blah-blah-blah, Transaction tr)
{
    // IO example
    Stream s = null;
    try
    {
        s = new FileStream(filename);
        tr.AddRollback(File.Delete(filename));
    }
    finally
    {
        if (s != null)
            s.close();
    }
}

一般的な使用法は次のとおりです。

Transaction tr = new Transaction();
try
{
    DoAction1(blah1, tr);
    DoAction2(blah2, tr);
    //...
}
catch (Exception ex)
{
    tr.ExecuteRollbacks();
    // queue the exception message to the user along with a command to repeat all the actions above
}

これは、現実の世界では少しトリッキーです

  • 実行アクションの前に一連のロックを取得する必要がある場合があります
  • ロールバック コード自体は例外サイレントにする必要があります (たとえば)

しかし、私はすでにこのアプローチに慣れており、アプリケーションはより安定しています。

于 2009-06-25T20:02:36.887 に答える
1

RuntimeExceptionありそうもないエラー状態に遭遇したときに、アプリケーション全体をタンクに入れないようにしてください。RuntimeExceptionこれはプログラマーのエラー用に予約する必要があり、プログラマーのエラーIOExceptionが原因ではない可能性が最も高いです。

代わりに、下位レベルの例外を上位レベルの例外にカプセル化し、再スローします。次に、呼び出しチェーンの上位レベルの例外を処理します。

例えば:

class SomeClass {

  public void doActions() {
    try {
      someAction();
    } catch (HigherLevelException e) {
      notifyUser();
    }

    someOtherUnrelatedAction();
  }

  public void someAction() throws HigherLevelException {  
    try {
      // user lower-level abstraction to do our bidding
    } catch(LowerLevelException e) {
      throw new HigherLevelException(e);
    }
  }

  public void someOtherUnrelatedAction() {
    // does stuff
  }
}

例外をスローしたコール スタックが、アプリケーションで何らかのタスクを実行していた可能性があります。アプリケーション全体を強制的にクラッシュさせる代わりに、RuntimeExceptionそのタスク中に問題が発生したときに何をすべきかを考えてください。たとえば、ファイルを保存しようとしましたか? クラッシュしないでください。代わりに、問題があったことをユーザーに通知してください。

于 2014-04-15T22:04:45.303 に答える