Java の例外処理メカニズムは比較的成熟しています。Java プログラムには例外の可能性がたくさんあります。これらの例外が事前に処理されないと、将来的にプログラムのクラッシュをデバッグすることが不可能になり、その例外を見つけるのが困難になります。例外の場所。この記事では、Java で例外とエラーを処理する方法について説明します。見てみましょう。
例外とエラー:
例外:
Java では、プログラムのエラーは主に構文エラーと意味エラーであり、プログラムをコンパイルして実行するときに発生するエラーを総称して例外と呼びます (VM (仮想マシン))。このようにして、VM はあなた (開発者) が間違いを犯し、それを修正する機会があることを知らせます。例外クラスは Java で例外を表すために使用され、異なる例外クラスは異なる例外を表します。ただし、Java のすべての例外には、Exception と呼ばれる基本クラスがあります。
エラー:
これは、適切なアプリケーションでは傍受できない深刻な問題を指します。ほとんどが異常です。エラーは VM の障害です (ただし、システム レベルのサービスであればどのようなものでも発生する可能性があります)。したがって、エラーの処理は難しく、通常の開発者 (もちろんあなたではありません) はメモリ オーバーフローなどのエラーを処理できません。 例外と同様、エラー クラスは Java でエラーを表すために使用され、異なるエラー クラスは異なるエラーを表します。 ただし、Java のすべてのエラーには、Error という基本クラスがあります。
要約すると、例外とエラーの最も本質的な違いは、例外は開発者が処理できるのに対し、エラーはシステムに固有のものであり、通常は処理できず、プログラマが処理する必要がないということです。
1. 例外は、通常の命令の実行を中断する、プログラムの実行中に発生するイベントです。
2. 許容可能なコード動作から逸脱するアクションまたはインスタンスです。
例外の構造分類:
1 . 実行時例外 (チェックされていない例外)
2. コンパイル時例外 (チェックされた例外)
実行時例外はすべてコンパイル例外です
Java では、Exception と Error は親クラス Throwable に共通するものを持っています。
エラー例外
runtimeException いくつかのサブクラス
1. java.lang.ArrayIndexOutOfBoundsException
配列インデックスの範囲外の例外。配列のインデックスが負の場合、または配列サイズ以上の場合にスローされます。
2. java.lang.ArithmeticException
算術条件例外。例: 整数のゼロ除算など。
3. java.lang.NullPointerException
Null ポインタ例外。この例外は、アプリケーションがオブジェクトが必要な場所で null を使用しようとするとスローされます。例: null オブジェクトのインスタンス メソッドの呼び出し、null オブジェクトの
属性へのアクセス、null オブジェクトの長さの計算、null をスローする throw ステートメントの使用など。
4.例外が見つかりません。この例外は、アプリケーションが文字列形式のクラス名に基づいてクラスを構築しようとしたが、CLASSPAH を走査した後に対応する名前のクラス ファイルが見つからなかった場合にスローされます。
例外処理:
try{}catch{}
try{}catch{}finally{} 例外の有無に関係なく、finally コード ブロックが実行されますtry{}finally{} も使用できます組み合わせて使用できますが、最終的に catch{} はできません
注: 継承関係では、サブクラスは親クラスのメソッドをオーバーライドし、例外をスローする範囲を親クラスより広くすることはできません
例外の使用
例外を使用するこの部分は主にデモンストレーション用です。コードは、コードを書く過程で通常遭遇するものです (もちろんごく一部です)。それに光を当ててみませんか。
例 1. この例は主には、2 つのメソッドを比較することによって、例外が発生した後のコードの実行フローを示しています。
public static void testException1() { int[] ints = new int[] { 1, 2, 3, 4 }; System.out.println("异常出现前"); try { System.out.println(ints[4]); System.out.println("我还有幸执行到吗");// 发生异常以后,后面的代码不能被执行 } catch (IndexOutOfBoundsException e) { System.out.println("数组越界错误"); } System.out.println("异常出现后"); } /*output:异常出现前数组越界错误常出现后*/ public static void testException2() { int[] ints = new int[] { 1, 2, 3, 4 }; System.out.println("异常出现前"); System.out.println(ints[4]); System.out.println("我还有幸执行到吗");// 发生异常以后,他后面的代码不能被执行 }
まず、この例の欠点を指摘します。 IndexOutofBoundsException はチェックされていない例外なので、キャプチャを表示するために try...catch... する必要はありませんが、私の目的は、キャプチャに対して別の処理メソッドを使用することです。同じ例外を実行して、どのような違いが生じるのか、そしてその結果を確認してください(ここではしばらくしか使用できません)。例外が発生すると、最初のメソッドは try ブロックから飛び出すだけですが、その背後にあるコードは引き続き実行されます。しかし、2 番目の種類は異なり、メソッドから直接飛び出すため、より困難です。最初のメソッドから、try...catch... は「トランザクション」保証であることがわかります。その目的は、異常な状況下でプログラムが完了することを保証することであると同時に、プログラマに通知することでもあります。プログラム情報内のエラーの詳細 (詳細はプログラマの設計に依存する場合があります)。
例 2. 例外を再スローする
public class Rethrow { public static void readFile(String file) throws FileNotFoundException { try { BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); } catch (FileNotFoundException e) { e.printStackTrace(); System.err.println("不知道如何处理该异常或者根本不想处理它,但是不做处理又不合适,这是重新抛出异常交给上一级处理"); //重新抛出异常 throw e; } } public static void printFile(String file) { try { readFile(file); } catch (FileNotFoundException e) { e.printStackTrace(); } } public static void main(String[] args) { printFile("D:/file"); } }
例外の意図は良いので、プログラムを修復してみますが、実際には修復できる可能性は非常に小さいため、エラー情報を記録するためによく使用されます。常に例外を処理することにうんざりしている場合は、例外を再スローすることで軽減される場合があります。この例外を変更せずに次のレベル、つまりこのメソッドを呼び出す人にスローし、彼に考えさせます。この観点から見ると、Java の例外 (もちろんチェック例外のことを指します) は、その出発点は良いものですが、私たちに多くの問題を引き起こしました。
例 3. 例外チェーンと例外損失の使用
ExceptionA,ExceptionB,ExceptionC public class ExceptionA extends Exception { public ExceptionA(String str) { super(); } } public class ExceptionB extends ExceptionA { public ExceptionB(String str) { super(str); } } public class ExceptionC extends ExceptionA { public ExceptionC(String str) { super(str); } }
例外損失の状況:
public class NeverCaught { static void f() throws ExceptionB{ throw new ExceptionB("exception b"); } static void g() throws ExceptionC { try { f(); } catch (ExceptionB e) { ExceptionC c = new ExceptionC("exception a"); throw c; } } public static void main(String[] args) { try { g(); } catch (ExceptionC e) { e.printStackTrace(); } } } /* exception.ExceptionC at exception.NeverCaught.g(NeverCaught.java:12) at exception.NeverCaught.main(NeverCaught.java:19) */
なぜ ExceptionC だけが出力され、ExceptionB は出力されないのでしょうか? これを自分で分析する必要があります
上記の状況は、欠落していることに相当します。これは例外であり、トラブルシューティングのプロセスでは非常に不利です。では、上記の状況に遭遇した場合はどうすればよいでしょうか? ここで例外チェーンが登場します。例外情報を保存し、元の例外を失わずに別の例外をスローします。
public class NeverCaught { static void f() throws ExceptionB{ throw new ExceptionB("exception b"); } static void g() throws ExceptionC { try { f(); } catch (ExceptionB e) { ExceptionC c = new ExceptionC("exception a"); //异常连 c.initCause(e); throw c; } } public static void main(String[] args) { try { g(); } catch (ExceptionC e) { e.printStackTrace(); } } } /* exception.ExceptionC at exception.NeverCaught.g(NeverCaught.java:12) at exception.NeverCaught.main(NeverCaught.java:21) Caused by: exception.ExceptionB at exception.NeverCaught.f(NeverCaught.java:5) at exception.NeverCaught.g(NeverCaught.java:10) ... 1 more */
initCause() メソッドは Throwable から継承しているため、この例外チェーンの特性はすべての例外で共有されます。
例 4. クリーンアップ作業
IO、JDBC などのリソースを消費する操作がある場合、クリーンアップ作業は不可欠です。使用後に適切に閉じないと、メモリリークという深刻な結果が生じます。例外が発生した場合、どのような状況であっても、リソースを適切かつタイムリーにクリーンアップできるようにメカニズムを設計する必要があります。これがついにです。
public void readFile(String file) { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader( new FileInputStream(file))); // do some other work } catch (FileNotFoundException e) { e.printStackTrace(); } finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } }
例は非常に簡単で、ファイルを読み取る例です。このような例は、JDBC 操作でも非常に一般的です。 (したがって、リソースをタイムリーかつ正しくクリーンアップすることは、プログラマの基本的な資質の 1 つであると思います。)
試してください...最後に、構造は、リソースが正しく閉じられていることを確認する手段でもあります。コードの実行中にリソースのクリーンアップを妨げるどのような例外が発生するかわからない場合は、 try を使用してこの「疑わしい」コードをラップし、最終的にリソースをクリーンアップできます。例を挙げてみましょう:
public void readFile() { BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader( new FileInputStream("file"))); // do some other work //close reader reader.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
この方法と前の方法の違いに注意してください。次の人はできるだけ早くリーダーを閉じる方が良いかもしれません。しかし、reader.close() より前であればいつでも例外が発生する可能性があり、そのようなコード構造では例外の発生を防ぐことができないため、裏目に出ることがよくあります。例外が発生した場所でプログラムが飛び出すため、後続のコードは実行できません (これは上記の例で証明されるはずです)。現時点では、try...finally を使用して次のように変換できます。
public void readFile() { BufferedReader reader = null; try { try { reader = new BufferedReader(new InputStreamReader( new FileInputStream("file"))); // do some other work // close reader } finally { reader.close(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
リソースを早めに閉じることは、良い動作です。時間がかかるほど、リソースを閉じるのを忘れる可能性が高くなります。このようにして、try...finally の調整は絶対確実であることが保証されます (面倒だと思わないでください。Java は非常に満足のいくものです)。
別の状況について話しましょう。コンストラクター メソッドでファイルを開いたり JDBC 接続を作成したりする場合、このリソースを他のメソッドで使用したいため、コンストラクター メソッドの早い段階でこのリソースを閉じることができません。では、私たちは迷っているでしょうか? 答えはノーです。次の例を見てください:
public class ResourceInConstructor { BufferedReader reader = null; public ResourceInConstructor() { try { reader = new BufferedReader(new InputStreamReader(new FileInputStream(""))); } catch (FileNotFoundException e) { e.printStackTrace(); } } public void readFile() { try { while(reader.readLine()!=null) { //do some work } } catch (IOException e) { e.printStackTrace(); } } public void dispose() { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } }
この部分は少し長くなりますが、例外は確かに使いやすいようで難しいものです。Java には、深く調査する必要があるものがまだたくさんあります。