こんにちは!あまり言いたくありませんが、プログラマーの仕事の大部分はエラーに対処することです。そしてほとんどの場合、自分のもので。たまたまですが、間違いを犯さない人はいません。そして、そのようなプログラムもありません。もちろん、エラーに対処するときに重要なことは、その原因を理解することです。そして、プログラムにはそのような理由がたくさんある可能性があります。ある時点で、Java の作成者は、プログラム内のこれらの非常に潜在的なエラーをどうすればよいのかという疑問に直面しました。それらを完全に避けることは非現実的です。プログラマは想像すら不可能なことを書くことができます :) これは、エラーを処理するメカニズムを言語に組み込む必要があることを意味します。つまり、プログラム内で何らかのエラーが発生した場合、さらなる作業のためにスクリプトが必要になります。エラーが発生した場合、プログラムは正確に何をすべきでしょうか? 今日はこのメカニズムについて説明します。そしてそれは「例外」と呼ばれます。
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
。結論:
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
各例外は Java の個別のクラスによって表されます。すべての例外クラスは、共通の「祖先」、つまり親クラスに由来しますThrowable
。例外クラスの名前は、通常、その発生の理由を簡単に反映しています。
FileNotFoundException
(ファイルが見つかりません)ArithmeticException
(算術演算を実行する場合は例外)ArrayIndexOutOfBoundsException
(配列セルの番号がその長さを超えて指定されています)。たとえば、長さ 10 の配列配列に対して cell array[23] をコンソールに出力しようとするとします。
Exception in thread "main"
うーん :/ 何も明らかではありません。どのような種類のエラーなのか、どこから発生したのかは不明です。有益な情報はありません。しかし、このような多様なクラスのおかげで、プログラマは、クラス名に含まれるエラーの種類とその考えられる原因という重要なことを自分で知ることができます。結局のところ、コンソールに表示されるものはまったく異なります。
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
何が問題なのか、そして問題を解決するために「どの方向に掘ればよいのか」がすぐに明らかになります。クラスの他のインスタンスと同様、例外はオブジェクトです。
例外のキャッチと処理
Java で例外を処理するには、特別なコード ブロック、try
およびcatch
がありますfinally
。 プログラマが例外の発生を予期するコードは、ブロック内に配置されますtry
。これは、必ずこの場所で例外が発生するという意味ではありません。これは、この問題がそこで発生する可能性があり、プログラマがそれを認識していることを意味します。受信すると予想されるエラーのタイプはブロックcatch
(「キャッチ」) に配置されます。ここには、例外が発生した場合に実行する必要があるすべてのコードが配置されます。以下に例を示します。
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
。catch
別の例外クラスをブロック括弧内に 渡しても、それは捕捉されません。
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!");
}
}
結論:
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
ブロック内のコードは、catch
このブロックをインターセプトするように「構成」しArithmeticException
、ブロック内のコードがtry
別のタイプ - をスローしたため機能しませんでしたFileNotFoundException
。のスクリプトは作成していないためFileNotFoundException
、プログラムは、 のデフォルトで表示される情報をコンソールに表示しますFileNotFoundException
。ここで3つのことに注意する必要があります。 初め。 try ブロック内のコード行で例外が発生すると、それ以降のコードは実行されなくなります。プログラムを実行すると、すぐにブロックに「ジャンプ」しますcatch
。例えば:
public static void main(String[] args) {
try {
System.out.println("Divide a number 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("Not");
System.out.println("will");
System.out.println("done!");
} 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
。この後、ブロックの 6 ~ 10 行目はtry
実行されなくなります。先ほど述べたように、プログラムはすぐにブロックの実行を開始しましたcatch
。 2番。 複数のブロックが存在する場合がありますcatch
。ブロック内のコードがtry
1 つではなく複数のタイプの例外をスローできる場合は、それぞれに対して独自のブロックを作成できます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 つのブロックを作成しましたcatch
。try
ブロック内に ,が発生した場合FileNotFoundException
、最初のブロックが実行されますcatch
。発生した場合ArithmeticException
、2 番目のものが実行されます。少なくとも 50 個のブロックを書くことができますcatch
が、もちろん、50 個の異なるタイプのエラーをスローする可能性のあるコードは書かない方が良いです :) 3 番目。 コードがスローする可能性のある例外をどうやって知ることができますか? もちろん、いくつかについて推測することはできますが、すべてを頭の中に留めておくことは不可能です。したがって、Java コンパイラは最も一般的な例外を認識しており、それらがどのような状況で発生する可能性があるかを認識しています。たとえば、コードを作成し、その動作中に 2 種類の例外が発生する可能性があることをコンパイラが認識している場合、それらを処理するまでコードはコンパイルされません。以下にその例を見ていきます。次に例外処理についてです。それらを処理するには2つの方法があります。最初の条件はすでに満たしています。メソッドはブロック内で独立して例外を処理できます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
この過程では、入出力(Input-Output)時にエラーが発生しやすくなります。ここで、コンパイラは、「おい、これらの例外のいずれかが発生した場合に何をすべきかをあなたが教えてくれるまで、私はこのコードを承認したりコンパイルしたりしません。そして、あなたが書いたコードに基づいてそれらは間違いなく起こる可能性があります!」。行き場がないので、両方を処理する必要があります。最初の処理オプションはすでにおなじみです。コードをブロックに配置し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("Error while inputting/outputting data from file!");
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 at one moment calls your printFirstString() method with the file it needs
printFirstString("C:\\Users\\Eugene\\Desktop\\testFile.txt");
}
エラー、コードがコンパイルされません。メソッド内にprintFirstString()
エラー処理スクリプトを記述しませんでした。したがって、この作業はこの方法を使用する人の肩にかかっています。つまり、メソッドはyourColleagueMethod()
同じ 2 つのオプションに直面することになります。 を使用してメソッドに「飛んできた」両方の例外を処理するtry-catch
か、それらをさらに転送する必要があります。
public static void yourColleagueMethod() throws FileNotFoundException, IOException {
//...the method does something
//...and at one moment calls your printFirstString() method with the file it needs
printFirstString("C:\\Users\\Eugene\\Desktop\\testFile.txt");
}
2 番目のケースでは、処理はスタック上の次のメソッド、つまり を呼び出すメソッドの肩にかかっていますyourColleagueMethod()
。このため、このようなメカニズムは「例外を上に投げる」または「上に渡す」と呼ばれます。を使用して例外をスローすると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 is the finally block!");
}
}
この例では、ブロック内のコードがfinally
両方の場合に実行されます。ブロック内のコードがtry
完全に実行され、例外がスローされない場合、ブロックは最後に起動されますfinally
。内部のコードtry
が中断され、プログラムがブロックにジャンプした場合catch
、内部のコードが実行された後もcatch
、ブロックは選択されたままになりますfinally
。なぜ必要なのでしょうか? その主な目的は、コードの必要な部分を実行することです。状況に関係なく完了しなければならない部分です。たとえば、プログラムによって使用されているリソースの一部が解放されることがよくあります。私たちのコードでは、ストリームを開いてファイルから情報を読み取り、それを に渡しますBufferedReader
。私たちのものはreader
閉じてリソースを解放する必要があります。これはどのような場合でも実行する必要があります。プログラムが期待どおりに動作するか例外をスローするかは関係ありません。これをブロック内で行うと便利です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 is the finally block!");
if (reader != null) {
reader.close();
}
}
}
これで、プログラムの実行中に何が起こったとしても、占有されたリソースを確実に処理できたことを確信できます :) 例外について知っておく必要があるのはそれだけではありません。エラー処理はプログラミングにおいて非常に重要なトピックです。これについては複数の記事が取り上げられています。次のレッスンでは、どのようなタイプの例外があるのか、そして独自の例外を作成する方法を学びます :) それではまた!
GO TO FULL VERSION