日常生活では、時には予期せぬ事態が発生します。たとえば、朝仕事に起きて携帯電話の充電器を探しましたが、見つかりませんでした。顔を洗うためにバスルームに行くと、水が止められています。車に乗りましたが、エンジンがかかりません。しかし、人はそのような予期せぬ状況に非常に簡単に対処することができます。この記事では、Java プログラムがこれらをどのように処理するかを理解していきます。
例外Javaとは何ですか
プログラミングの世界では、プログラムの実行中にエラーや予期せぬ状況が発生することを例外と呼びます。プログラムでは、ユーザーの誤った操作、ディスク上に必要なリソースの欠如、ネットワーク経由でのサーバーへの接続の切断などの結果として例外が発生することがあります。プログラム実行中の例外は、プログラミング エラーや API の誤った使用によって発生することもあります。私たちの世界とは異なり、プログラムはそのような状況で何をすべきかを明確に認識している必要があります。Java は、この目的のために例外メカニズムを提供します。
キーワードについて簡単に説明すると、try、catch、finally、throws
Java での例外処理は、プログラム内での次のキーワードの使用に基づいています。
- try - 例外が発生する可能性のあるコードのブロックを定義します。
- catch – 例外が処理されるコードのブロックを定義します。
- finally – コードのブロックを定義します。これはオプションですが、存在する場合は、try ブロックの結果に関係なく実行されます。
これらのキーワードは、プログラム コード内で特別な処理構造を作成するために使用されます: try{}catch、try{}catch{}finally、try{}finally{}。
- throw – 例外を発生させるために使用されます。
- throws – メソッドが例外をスローする可能性があることを警告するためにメソッド シグネチャで使用されます。
Java プログラムでのキーワードの使用例:
public String input() throws MyException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String s = null;
try {
s = reader.readLine();
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
reader.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
if (s.equals("")) {
throw new MyException("String can not be empty!");
}
return s;
}
なぜ例外メカニズムが必要なのでしょうか?
実際の例を見てみましょう。高速道路上に、耐荷重が制限された緊急橋のある区間があると想像してください。橋の耐荷重を超える質量の車両が橋を渡ろうとすると、橋が崩壊する可能性があり、ドライバーにとっては、控えめに言っても例外的な状況になる可能性があります。このような事態を防ぐために、ロードサービスでは事前に道路に警告標識を設置しています。車の運転手は、警告標識を見ながら、自分の車の重量と橋の上を走行できる重量を比較します。それを超えると遠回りすることになる。道路サービスのおかげで、トラックの運転手は、第一に、事前にルートを変更する機会が与えられ、第二に、幹線道路の危険性について警告され、最後に、幹線道路の使用が不可能であることについて警告されました。特定の条件下での橋。
プログラム内の例外を防止して解決してプログラムを継続できる機能が、Java で例外を使用する理由の 1 つです。例外メカニズムを使用すると、受信データを検証 (チェック) することで、作成したコード (プログラミング インターフェイス) をユーザーによる悪用から保護することもできます。では、ちょっと交通警察になってみましょう。まず、自動車運転者がトラブルに巻き込まれる可能性のある場所を知っておく必要があります。次に、警告標識を準備して設置する必要があります。最後に、主要ルートに危険があった場合に備えて、迂回ルートを提供する必要があります。Java では、例外メカニズムは同様に機能します。プログラム開発段階では、try{} ブロックを使用してコードの危険なセクションを例外から「保護」し、catch{} ブロックを使用して「バックアップ」パスを提供し、finally{} ブロックで実行されるコードを記述します。あらゆる結果をもたらすプログラム。「緊急ルート」を提供できない場合、または意図的にユーザーに選択を委ねたい場合は、少なくともユーザーに危険について警告する必要があります。なぜ?途中で何の警告標識にも遭遇せずに、車で渡ることができない緊急橋に到達するドライバーの憤りを想像してみてください。プログラミングでは、クラスやメソッドを記述するときに、他の開発者がプログラム内でクラスやメソッドを使用するコンテキストを常に予測できるわけではないため、例外状況を解決するための 100% 正しいパスを予測することはできません。同時に、コードのユーザーに例外の可能性について警告することをお勧めします。Java の例外メカニズムでは、throws を使用してこれを行うことができます。これは本質的に、例外をスローするメソッドの一般的な動作を宣言するため、Java で例外を処理するコードを作成するのはメソッドのユーザーに任されます。
「トラブル」の警告
メソッド内で例外を処理する予定はないが、起こり得る例外状況についてメソッドのユーザーに警告したい場合は、 throws キーワードを使用します。メソッド シグネチャ内のこのキーワードは、特定の条件下でメソッドが例外をスローする可能性があることを意味します。この警告はメソッド インターフェイスの一部であり、ユーザーに例外ハンドラーの実装をカスタマイズする権利を与えます。throws の後に、スローされる例外のタイプを示します。これらは通常、 Java
Exceptionクラスの子孫です。Java はオブジェクト指向言語であるため、Java の例外はすべてオブジェクトです。
Javaの例外階層
プログラムの実行中にエラーが発生すると、JVM ランタイムは Java 例外階層 (共通の「祖先」から継承される可能性のある例外のセット)、つまり Throwable クラスから必要なタイプのオブジェクトを作成します。プログラム内で発生する例外状況は、次の 2 つのグループに分類できます。
- プログラムのさらなる正常な動作の回復が不可能な状況
- 回復は可能です。
最初のグループには、
Errorクラスから継承された例外が発生する状況が含まれます。これらは、JVM 障害、メモリ オーバーフロー、システム クラッシュの結果としてプログラムの実行中に発生するエラーです。これらは通常、ソフトウェアを使用して解決できない重大な問題を示しています。Java のこのタイプの例外は、コンパイル段階では未チェックとして分類されます。このグループには、RuntimeException (プログラムの実行中に JVM によって生成される例外、
例外クラスの継承子) も含まれます。多くの場合、これらはプログラミング エラーによって引き起こされます。これらの例外はコンパイル時にチェックされないため、それらを処理するコードを作成する必要はありません。2 番目のグループには、プログラムを作成する段階で予見され、処理コードを作成する必要がある例外的な状況が含まれます。このような例外はチェックされます。例外を処理する場合の Java 開発者の仕事の大部分は、そのような状況を処理することです。
例外の作成
プログラムの実行中に、JVM によって、または
throwステートメントを使用して手動で例外がスローされます。これにより、メモリ内に例外オブジェクトが作成され、JVM 例外ハンドラーが例外を処理する方法を見つけようとしている間、メイン プログラム コードの実行が中断されます。
例外処理
Java で例外処理を提供するコード ブロックの作成は、プログラム内で try{}catch、try{}catch{}finally、try{}finally{} コンストラクトを使用して行われます。
try ブロックで例外が発生すると、次の catch ブロックで例外ハンドラーが検索されます。catch にこのタイプの例外のハンドラーが含まれている場合、制御はそれに渡されます。そうでない場合、JVM は、適切なキャッチが見つかるまで、メソッド呼び出しのチェーン内でその例外タイプのハンドラーを探します。catch ブロックが実行された後、制御はオプションの
finallyブロックに渡されます。適切な catch ブロックが見つからない場合、JVM はプログラムの実行を停止し、finally ブロック コードが存在する場合は以前に実行したメソッド呼び出しのスタック (
スタック トレース)を表示します。例外処理の例:
public class Print {
void print(String s) {
if (s == null) {
throw new NullPointerException("Exception: s is null!");
}
System.out.println("Inside method print: " + s);
}
public static void main(String[] args) {
Print print = new Print();
List list= Arrays.asList("first step", null, "second step");
for (String s:list) {
try {
print.print(s);
}
catch (NullPointerException e) {
System.out.println(e.getMessage());
System.out.println("Exception was processed. Program continues");
}
finally {
System.out.println("Inside bloсk finally");
}
System.out.println("Go program....");
System.out.println("-----------------");
}
}
}
mainメソッド の結果:
Inside method print: first step
Inside bloсk finally
Go program....
-----------------
Exception: s is null!
Exception was processed. Program continues
Inside bloсk finally
Go program....
-----------------
Inside method print: second step
Inside bloсk finally
Go program....
-----------------
このブロックは
finally
通常、try ブロックで開かれたストリームを閉じるか、リソースを解放するために使用されます。ただし、プログラムを作成するときに、すべてのリソースの終了を常に追跡できるとは限りません。
try-with-resources
私たちの作業を楽にするために、Java 開発者は、try ブロックで開かれたリソースを自動的に閉じる構造を提供してくれました。最初の例は次のように書き換えることができます
try-with-resources
。
public String input() throws MyException {
String s = null;
try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
s = reader.readLine();
} catch (IOException e) {
System.out.println(e.getMessage());
}
if (s.equals("")){
throw new MyException ("String can not be empty!");
}
return s;
}
バージョン 7 以降の Java の機能のおかげで、さまざまなタイプの例外のキャッチを 1 つのブロックに結合して、コードをよりコンパクトで読みやすくすることもできます。例えば:
public String input() {
String s = null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
s = reader.readLine();
if (s.equals("")) {
throw new MyException("String can not be empty!");
}
} catch (IOException | MyException e) {
System.out.println(e.getMessage());
}
return s;
}
結果
Java で例外を使用すると、「バックアップ」パスを使用してプログラムのフォールト トレランスを向上させることができ、catch ブロックを使用してメイン コードのロジックを例外処理コードから分離することができ、また、委任する機会も得られます。コードのユーザーにスローを使用して例外処理を提供します。
GO TO FULL VERSION