CodeGym /Java Blog /ランダム /例外: キャッチと処理
John Squirrels
レベル 41
San Francisco

例外: キャッチと処理

ランダム グループに公開済み
やあ!あまり言いたくないのですが、プログラマーの仕事の大部分はエラーに対処することです。ほとんどの場合、その人自身のものです。間違いを犯さない人はいないことが分かりました。そして、そのようなプログラムもありません。 例外: キャッチと処理 - 1 もちろん、エラーに対処するときは、その原因を理解することが重要です。。そして、多くのことがプログラムにバグを引き起こす可能性があります。ある時点で、Java の作成者は、最も可能性の高いプログラミング エラーにどう対処すべきかを自問しました。それらを完全に回避することは現実的ではありません。プログラマーは、あなたが想像すらできないものを書くことができます。:) したがって、言語にエラーを処理するためのメカニズムを与える必要があります。言い換えれば、プログラムにエラーがあった場合、次に何をするかを示す何らかのスクリプトが必要になります。エラーが発生した場合、プログラムは正確に何をすべきでしょうか? 今日はこのメカニズムについて説明します。それは「Java の例外」と呼ばれます。

例外とは何ですか?

例外とは、プログラムの実行中に発生する例外的な計画外の状況です。 例外はたくさんあります。たとえば、ファイルからテキストを読み取り、最初の行を表示するコードを作成したとします。

public class Main {

   public static void main(String[] args) throws IOException {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   }
}
しかし、そのようなファイルがなかったらどうでしょうか。プログラムは例外を生成します: FileNotFoundException。出力: スレッド "main" の例外 java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (システムは指定されたパスを見つけることができません) Java では、各例外は別個のクラスで表されます。 これらすべての例外クラスは、共通の「祖先」、つまりThrowable親クラスから派生します。例外クラスの名前は、通常、例外が発生した理由を簡潔に反映しています。
  • FileNotFoundException(ファイルが見つかりませんでした)

  • ArithmeticException(数学演算の実行中に例外が発生しました)

  • ArrayIndexOutOfBoundsException(インデックスが配列の境界を超えています)。たとえば、要素が 10 個しかない配列の位置 23 を表示しようとすると、この例外が発生します。
Java には、そのようなクラスが合計で約400あります。なぜそんなにたくさんあるのでしょうか?プログラマが作業しやすいようにするため。これを想像してください。プログラムを作成すると、その実行中に次のような例外が生成されます。

Exception in thread "main"
うーん。:/ それはあまり役に立ちません。エラーが何を意味するのか、どこから発生したのかは明らかではありません。ここには役立つ情報はありません。しかし、Java には多種多様な例外クラスが存在するため、プログラマは最も重要なこと、つまりエラーの種類とその考えられる原因 (クラス名に埋め込まれている) を得ることができます。それはまったく別のことです

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (The system cannot find the specified path)
何が問題なのか、問題を解決するためにどこから調査を始めればよいのかがすぐにわかります。 例外は、他のクラスのインスタンスと同様、オブジェクトです。

例外のキャッチと処理

Java には、例外を処理するための特別なコード ブロックがあります:tryおよび。 プログラマが例外が発生する可能性があると判断したコードは、ブロック内に配置されます。ただし、ここで例外が発生するという意味ではありません。これは、ここでそれが発生する可能性があり、プログラマはこの可能性を認識していることを意味します。発生すると予想されるエラーの種類がブロック内に配置されます。これには、例外が発生した場合に実行する必要があるすべてのコードも含まれています。以下に例を示します。 catchfinally例外: キャッチと処理 - 2trycatch

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Error! File not found!");
   }
}
出力: エラー! ファイルが見つかりません! コードを 2 つのブロックに配置します。最初のブロックでは、「ファイルが見つかりません」エラーが発生することが予想されます。これがtryブロックです。2 つ目では、エラーが発生した場合に何を行うかをプログラムに指示します。そして、具体的なエラーの種類は次のとおりですFileNotFoundException。ブロックの括弧内に別の例外クラスを入れるとcatchFileNotFoundException捕捉されません。

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (ArithmeticException e) {

       System.out.println("Error! File not found!");
   }
}
出力: スレッド「main」の例外 java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (システムは指定されたパスを見つけることができません)ブロック 内のコードはcatch、「構成」されたため実行されませんでした。このブロックを catch にするArithmeticExceptionと、ブロック内のコードはtry別の型をスローしました: FileNotFoundException。を処理するコードを作成していないFileNotFoundExceptionため、プログラムは のデフォルト情報を表示しますFileNotFoundException。ここで 3 つのことに注意する必要があります。 一番。ブロック内のどこかの行で例外が発生するとtry、その後のコードは実行されません。プログラムを実行すると、すぐにそのcatchブロックに「ジャンプ」します。例えば:

public static void main(String[] args) {
   try {
       System.out.println("Divide by zero");
       System.out.println(366/0);// This line of code will throw an exception

       System.out.println("This");
       System.out.println("code");
       System.out.println("will not");
       System.out.println("be");
       System.out.println("executed!");

   } catch (ArithmeticException e) {

       System.out.println("The program jumped to the catch block!");
       System.out.println("Error! You can't divide by zero!");
   }
}
出力: ゼロ除算 プログラムは catch ブロックにジャンプしました。エラー!ゼロで割ることはできません。 ブロックの 2 行目ではtry、0 で除算しようとします。その結果、 が返されますArithmeticException。したがって、tryブロックの 3 行目から 9 行目は実行されません。前述したように、プログラムはすぐにcatchブロックの実行を開始します。 ナンバー2。複数のブロックが存在する場合がありますcatchブロック内のコードが 1 つではなく、複数の異なるタイプの例外をスローする可能性がある場合は、それぞれに対してブロックを try作成できます。catch

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       System.out.println(366/0);
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
      
       System.out.println("Error! File not found!");
      
   } catch (ArithmeticException e) {

       System.out.println("Error! Division by 0!");
      
   }
}
この例では、2 つのブロックを作成しましたcatchFileNotFoundExceptionブロック内で が発生するとtry、最初のcatchブロックが実行されます。がArithmeticException発生すると、2 番目のブロックが実行されます。catch必要に応じて、50 ブロックを書き込むこともできます。もちろん、50 種類の例外をスローする可能性のあるコードは作成しない方がよいでしょう。:) 3番目。コードがスローする可能性のある例外をどのようにして知ることができますか? まあ、いくつかは推測できるかもしれませんが、すべてを頭の中に留めておくのは不可能です。 したがって、Java コンパイラは、最も一般的な例外と、それらが発生する可能性のある状況を認識しています。 たとえば、コンパイラが 2 種類の例外をスローする可能性があることを認識しているコードを作成した場合、それらの例外を処理するまでコードはコンパイルされません。以下にその例を示します。次に、例外処理について少し説明します。例外を処理するには 2 つの方法があります。1 つ目についてはすでに説明しています。メソッドは例外自体をcatch()ブロック内で処理できます。2 番目のオプションがあります。メソッドは呼び出しスタックに例外を再スローできます。どういう意味ですか?たとえば、printFirstString()ファイルを読み取り、その最初の行を表示する同じメソッドを持つクラスがあります。

public static void printFirstString(String filePath) {

   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
現時点では、未処理の例外があるため、コードはコンパイルできません。1 行目では、ファイルへのパスを指定します。コンパイラは、そのようなコードが簡単にFileNotFoundException. 3 行目では、ファイルからテキストを読み取ります。このプロセスでは、簡単にIOException(入力/出力エラー) が発生する可能性があります。ここでコンパイラは、「おい、私はこのコードを承認しないし、これらの例外のいずれかが発生した場合にどうすればよいかをあなたが教えてくれるまでコンパイルはしない。そして、あなたが書いたコードに基づいて例外は確かに起こる可能性がある」と言いました。 !」 これを回避する方法はありません。両方に対処する必要があります。最初の例外処理方法についてはすでに知っています。コードをブロックに配置しtry、2 つのcatchブロックを追加する必要があります。

public static void printFirstString(String filePath) {

   try {
       BufferedReader reader = new BufferedReader(new FileReader(filePath));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error, file not found!");
       e.printStackTrace();
   } catch (IOException e) {
       System.out.println("File input/output error!");
       e.printStackTrace();
   }
}
しかし、これが唯一の選択肢ではありません。メソッド内にエラー処理コードを記述する代わりに、単純に例外を上位にスローすることもできます。throwsこれは、メソッド宣言内の キーワードを使用して行われます。

public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
キーワード の後にthrows、メソッドがスローする可能性のあるすべてのタイプの例外のコンマ区切りのリストを示します。なぜ?printFirstString()ここで、誰かがプログラム内のメソッドを呼び出したい場合は、その人 (あなたではなく) が例外処理を実装する必要があります。たとえば、プログラムの別の場所で、同僚の 1 人があなたのprintFirstString()メソッドを呼び出すメソッドを作成したとします。

public static void yourColleagueMethod() {

   // Your colleague's method does something

   //...and then calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
エラーが発生します。このコードはコンパイルできません! メソッド内に例外処理コードを記述しませんでしたprintFirstString()その結果、この作業はこのメソッドを使用する人の肩にかかっています。 つまり、methodWrittenByYourColleague()メソッドには同じ 2 つのオプションがあります。try-catchブロックを使用して両方の例外を処理するか、例外を再スローする必要があります。

public static void yourColleagueMethod() throws FileNotFoundException, IOException {
   // The method does something

   //...and then calls your printFirstString() method with the file it needs
   printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
2 番目のケースでは、呼び出しスタック内の次のメソッド (呼び出し側) がmethodWrittenByYourColleague()例外を処理する必要があります。このため、これを「例外をスローまたは渡す」と呼んでいます。キーワードを使用して例外を上向きにスローするとthrows、コードはコンパイルされます。この時点で、コンパイラーは「わかった、わかった。コードには潜在的な例外が多数含まれていますが、コンパイルします。ただし、この会話に戻ります!」と言っているようです。 また、未処理の例外があるメソッドを呼び出すと、コンパイラはその約束を果たし、その例外について再度通知します。最後にブロックについてお話しますfinally(ダジャレですみません)。これは、例外処理三頭政治の最後の部分ですtry-catch-finally

public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Error! File not found!");
       e.printStackTrace();
   } finally {
       System.out.println ("And here's the finally block!");
   }
}
この例では、ブロック内のコードはfinallyどちらの場合でも実行されます。 ブロック内のコードがtry例外をスローせずに完全に実行されると、finallyブロックは最後に実行されます。ブロック内のコードがtry例外によって中断され、プログラムがそのcatchブロックにジャンプした場合でも、finallyブロックはブロック内のコードの後に​​引き続き実行されますcatchなぜこれが必要なのでしょうか? その主な目的は、必須コード、つまり状況に関係なく実行する必要があるコードを実行することです。たとえば、プログラムによって使用されているリソースの一部が解放されることがよくあります。コードでは、ストリームを開いてファイルから情報を読み取り、それをオブジェクトに渡しますBufferedReader。 リーダーを閉じてリソースを解放する必要があります。これは、プログラムが正常に動作するとき、および例外をスローするときなど、何があっても実行する必要があります。ブロックfinallyはこれを行うのに非常に便利な場所です。

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

   BufferedReader reader = null;
   try {
       reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   } finally {
       System.out.println ("And here's the finally block!");
       if (reader != null) {
           reader.close();
       }
   }
}
これで、プログラムの実行中に何が起こっても、リソースを確実に管理できるようになりました。:) 例外について知っておくべきことはそれだけではありません。エラー処理はプログラミングにおいて非常に重要なトピックです。多くの記事がそれについて取り上げられています。次のレッスンでは、どのような種類の例外があるのか​​、また独自の例外を作成する方法について説明します。:) それではまた!
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION