1.例外をキャッチします。
Javaでは、例外をスローする可能性のあるステートメントはすべてtry...catchでキャッチできます。例外を引き起こす可能性のあるステートメントをtry{...}に入れ、catchを使用して対応する例外とそのサブクラスをキャッチします。
1.複数のcatchステートメント
複数のcatchステートメントを使用でき、各catchは対応するExceptionとそのサブクラスをキャッチします。JVMは例外をキャッチした後、catchステートメントを上から下に一致させます。特定のcatchに一致した後、catchコードブロックを実行し、その後、一致を継続しません。簡単に言えば、複数のcatchステートメントのうち1つだけを実行できます。例えば:
public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (IOException e) {
System.out.println(e);
} catch (NumberFormatException e) {
System.out.println(e);
}
}
複数のキャッチがある場合、キャッチの順序は非常に重要であり、サブクラスを最初に記述する必要があります。次に例を示します。
public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (IOException e) {
System.out.println("IO error");
} catch (UnsupportedEncodingException e) { // 永远捕获不到
System.out.println("Bad encoding");
}
}
上記のコードの場合、UnsupportedEncodingExceptionはIOExceptionのサブクラスであるため、キャッチできません。UnsupportedEncodingExceptionがスローされると、catch(IOException e){...}によってキャッチおよび実行されます。したがって、正しいアプローチは、サブクラスフィールドを最初に配置することです。
public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (UnsupportedEncodingException e) {
System.out.println("Bad encoding");
} catch (IOException e) {
System.out.println("IO error");
}
}
2.最後にステートメント
例外があるかどうかに関係なく、クリーンアップ作業などのいくつかのステートメントを実行する必要があります。実行ステートメントを数回記述できます。通常の実行を試行し、キャッチごとに再度記述します。次に例を示します。
public static void main(String[] args) {
try {
process1();
process2();
process3();
System.out.println("中国抗击疫情必将胜利!!!"); //这行代码是我们想必须执行的
} catch (UnsupportedEncodingException e) {
System.out.println("Bad encoding");
System.out.println("END");
} catch (IOException e) {
System.out.println("IO error");
System.out.println("END");
}
}
ただし、このコード行はSystem.out.println( "中国がエピデミックとの戦いに勝ちます!!!");ただし、前の呼び出しメソッドがスローされて例外が発生した場合、このコード行は実行されません。 finallyブロックを使用して、エラーの有無にかかわらず実行されることを確認できます。また、上記のコードは次のように書き直すことができます。
public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (UnsupportedEncodingException e) {
System.out.println("Bad encoding");
} catch (IOException e) {
System.out.println("IO error");
} finally {
System.out.println("中国抗击疫情必将胜利!!!"); //这行代码是我们想必须执行的
}
}
最終的にいくつかの機能に注意してください:
1.finallyステートメントは必要ありません。書くこともできなくてもかまいません。
2.finallyは常に最後に実行されます。
例外が発生しない場合、try {...}ブロックは正常に実行され、最後に実行されます。例外が発生した場合、try {...}ブロックの実行が中断され、一致するcatchブロックの実行がジャンプされ、最後に最後に実行されます。いくつかのコードを実行する必要があることを確認するためにfinallyが使用されていることがわかります。
場合によっては、次のように、catchなしでtry...finally構造を使用することもできます。
void process(String file) throws IOException {
try {
...
} finally {
System.out.println("中国抗击疫情必将胜利!!!"); //这行代码是我们想必须执行的
}
}
3.さまざまな例外をキャッチします。
一部の例外の処理ロジックが同じであるが、例外自体の前に継承関係がない場合は、次のように複数のcatchステートメントを記述する必要があります。
public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (IOException e) {
System.out.println("Bad input");
} catch (NumberFormatException e) {
System.out.println("Bad input");
} catch (Exception e) {
System.out.println("Unknown error");
}
}
IOExceptionとNumberFormatExceptionを処理するためのコードは同じであるため、次のように、彼女の二重使用を組み合わせることができます。
public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (IOException | NumberFormatException e) { // IOException或NumberFormatException
System.out.println("Bad input");
} catch (Exception e) {
System.out.println("Unknown error");
}
}
try ... catch ... finalを使用して、例外の概要をキャッチします。
1.複数のcatchステートメントの一致順序は非常に重要であり、サブクラスを最初に配置する必要があります。
2. finallyステートメントは、例外の有無にかかわらず実行されることを保証し、オプションです。
3. catchステートメントは、複数の非継承例外に一致する場合もあります。
2.例外をスローします。
1.異常な伝播経路:
メソッドが例外をスローするときに、現在のメソッドが例外をキャッチしない場合、try ... catchがキャッチされるまで、例外は上位レベルの呼び出しメソッドにスローされます。
public class Main {
public static void main(String[] args) {
try {
process1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void process1() {
process2();
}
static void process2() {
Integer.parseInt(null); // 会抛出NumberFormatException
}
}
メソッドの呼び出しスタックは、printStackTrace()を介して出力できます。次に例を示します。
java.lang.NumberFormatException: null
at java.base/java.lang.Integer.parseInt(Integer.java:614)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at Main.process2(Main.java:16)
at Main.process1(Main.java:12)
at Main.main(Main.java:5)
printStackTrace()は、エラーのデバッグに非常に役立ちます。上記の情報は、次のことを意味します。numberFormatExceptionがjava.lang.Integer.parseIntメソッドでスローされます。下から上に、呼び出し元のレイヤーは次のとおりです。
1.main()はprocess1();を呼び出します。
2.process1()はprocess2();を呼び出します。
3.process2()はInteger.parseInt(String);を呼び出します。
4.Integer.parseInt(String)调用Integer.parseInt(String、int);
Integer.javaのソースコードを見ると、スローする例外メソッドのコードは次のようになっていることがわかります。
public static int parseInt(String s, int radix) throws NumberFormatException {
if (s == null) {
throw new NumberFormatException("null");
}
...
}
2.例外をスローします
ユーザーが不正な文字を入力するなどのエラーが発生した場合、例外をスローできます。例外をスローするにはどうすればよいですか。上記のInteger.parseInt()メソッドを参照すると、例外のスローは2つのステップに分かれています。
1.例外のインスタンスを作成します。
2.throwステートメントを使用してスローします。
例えば:
void process2(String s) {
if (s==null) {
NullPointerException e = new NullPointerException();
throw e;
//throw new NullPointerException();
}
}
実際、例外をスローするほとんどのコードは、上記のコメントアウトまたは次のような行に結合されます。
void process2(String s) {
if (s==null) {
throw new NullPointerException();
}
}
メソッドが例外をキャッチしてから、キャッチ自体に新しい例外をスローする場合、スローされた例外のタイプを変換するのと同じです。
void process1(String s) {
try {
process2();
} catch (NullPointerException e) {
throw new IllegalArgumentException();
}
}
void process2(String s) {
if (s==null) {
throw new NullPointerException();
}
}
process2()がNullPointerExceptionをスローすると、process1()によってキャッチされ、IllegalArgumentException()がスローされます。IllegalArgumentExceptionがmain()でキャッチされた場合、wineは次のように例外スタックを出力して表示します。
public class Main {
public static void main(String[] args) {
try {
process1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void process1() {
try {
process2();
} catch (NullPointerException e) {
throw new IllegalArgumentException();
}
}
static void process2() {
throw new NullPointerException();
}
}
印刷された例外スタックは次のようになります。
java.lang.IllegalArgumentException
at Main.process1(Main.java:15)
at Main.main(Main.java:5)
これは、新しい例外が元の例外または基本例外の情報を失い、元の例外NullPointerExceptionの情報を表示できなくなったことを示しています。完全な例外スタック情報をトレースするには、例外を作成するときに、元のExceptionインスタンスを渡すと、新しいExceptionが元のException情報を保持できます。上記のコードを次のように変更します。
public class Main {
public static void main(String[] args) {
try {
process1();
} catch (Exception e) {
e.printStackTrace();
}
}
static void process1() {
try {
process2();
} catch (NullPointerException e) {
throw new IllegalArgumentException(e);
}
}
static void process2() {
throw new NullPointerException();
}
}
上記のコードを実行すると、出力される例外スタックは次のようになります。
java.lang.IllegalArgumentException: java.lang.NullPointerException
at Main.process1(Main.java:15)
at Main.main(Main.java:5)
Caused by: java.lang.NullPointerException
at Main.process2(Main.java:20)
at Main.process1(Main.java:13)
注:原因:Xxxは、キャッチされたIllegalArgumentExceptionが問題の根本的な原因ではないことを示します。根本的な原因は、Main.process2()メソッドでスローされたNullPointerExceptionです。コード内の生の例外情報を取得するには、Throwable.getCause()メソッドを使用できます。nullが返された場合は、その例外が問題の原因となったルート例外であることを意味します。完全な例外スタック情報を使用して、問題を解決するためにコードをすばやく見つけて変更できます。
例外をキャッチして再度スローするときは、最初の犯罪現場をより早く見つけることができるように、必ず元の例外を保持してください。!!
tryまたはcatchブロックで例外をスローした場合でも、finallyブロックは実行されますか?例えば:
public class Main {
public static void main(String[] args) {
try {
Integer.parseInt("abc");
} catch (Exception e) {
System.out.println("catched");
throw new RuntimeException(e);
} finally {
System.out.println("finally");
}
}
}
上記のコードの実行結果は次のとおりです。
catched
finally
Exception in thread "main" java.lang.RuntimeException: java.lang.NumberFormatException: For input string: "abc"
at Main.main(Main.java:8)
Caused by: java.lang.NumberFormatException: For input string: "abc"
at ...
1行目はcatchステートメントブロックが入力されたことを示すcatchedを出力し、2行目はfinallyステートメントブロックが実行されたことを示すfinallyを出力するため、catchで例外がスローされても、最終的に実行すると、JVMは最初に最終的に実行し、次に例外をスローします。
3.例外シールド:
finallyステートメントの実行時に例外がスローされた場合、catchブロックは引き続きスローできますか?例えば:
public class Main {
public static void main(String[] args) {
try {
Integer.parseInt("abc");
} catch (Exception e) {
System.out.println("catched");
throw new RuntimeException(e);
} finally {
System.out.println("finally");
throw new IllegalArgumentException();
}
}
}
上記のコードを実行し、次のように例外情報を見つけます。
catched
finally
Exception in thread "main" java.lang.IllegalArgumentException
at Main.main(Main.java:11)
コンソール出力は、最終的に例外をスローした後、1つの例外しかスローできないため、catchでスローされる予定だった例外が「消える」ことを示しています。スローされない例外は、「マスクされた」例外(抑制された例外)と呼ばれます。まれに、すべての例外を知る必要があるので、すべての例外情報を保存するにはどうすればよいですか?この方法では、最初に元のフィールドを変数に保存してから、Throwable.addSuppressed()を呼び出し、元のフィールドを追加して、最後に次のようにスローします。
public class Main {
public static void main(String[] args) throws Exception {
Exception origin = null;
try {
System.out.println(Integer.parseInt("abc"));
} catch (Exception e) {
origin = e;
throw e;
} finally {
Exception e = new IllegalArgumentException();
if (origin != null) {
e.addSuppressed(origin);
}
throw e;
}
}
}
catch例外とfinallythrowの両方の例外がマスクされている場合でも、finallythrowed例外には次の例外が含まれています。
Exception in thread "main" java.lang.IllegalArgumentException
at Main.main(Main.java:11)
Suppressed: java.lang.NumberFormatException: For input string: "abc"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Integer.parseInt(Integer.java:652)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at Main.main(Main.java:6)
抑制されたすべての例外は、Throwable.getSuppressed()を介して取得できます。ほとんどの場合、最後に例外をスローしないでください。したがって、通常、抑制された例外については気にしません。
例外の概要のスロー:
1. printStackTrace()を呼び出すと、例外伝播スタックを出力できます。これは、プログラムのデバッグに非常に効果的です。
2.例外がキャッチされ、新しい例外が再度スローされた場合、元の例外情報を保持する必要があります。
3.通常、finallyで例外をスローしません。最終的に例外がスローされた場合は、元の例外を元の例外に追加する必要があります。呼び出し元は、Throwable.getSuppressed()を介して、追加されたすべての抑制された例外を取得できます。
3.カスタム例外:
コードで例外をスローする必要がある場合は、JDKですでに定義されている例外を使用してみてください。例:パラメータタイプが無効である場合、IllegalArgumentExceptionをスローする必要があります。
static void process1(int age) {
if (age <= 0) {
throw new IllegalArgumentException();
}
}
もちろん、大規模なプロジェクトでは、新しい例外タイプをカスタマイズできますが、適切な継承システムを維持することが非常に重要です。通常は、例外を「ルート例外」としてカスタマイズしてから、さまざまなサービスを派生させます。例外のタイプ。ルート例外は適切な例外から派生する必要があります。通常、RuntimeExceptionから派生することをお勧めします。
public class BaseException extends RuntimeException {
}
他のすべての例外タイプは、ルート例外から派生させることができます。
public class UserNotFoundException extends BaseException {
}
public class LoginFailedException extends BaseException {
}
...
カスタムルート例外は、複数のコンストラクター(できればRuntimeExceptionに対応する)を提供する必要があります。
public class BaseException extends RuntimeException {
public BaseException() {
super();
}
public BaseException(String message, Throwable cause) {
super(message, cause);
}
public BaseException(String message) {
super(message);
}
public BaseException(Throwable cause) {
super(cause);
}
}
上記のコンストラクターのRuntimeExceptionのネイティブ実装を参照してください。このようにして、例外がスローされたときに、適切なコンストラクターを選択できます。
カスタム例外の概要:
1.例外がスローされた場合は、JDKですでに定義されている例外タイプを可能な限り再利用します。
2.例外システムをカスタマイズするときは、RuntimeExceptionクラスからルート例外を派生させてから、ルート例外から他のタイプの例外を派生させることをお勧めします。
3.例外をカスタマイズするときは、RuntimeExceptionクラスを模倣し、複数の構築メソッドを提供するようにしてください。