7.2例外をキャッチ
あなたは今の例外をスローする方法を知っています。それは簡単です:あなたは忘れて投げます。もちろん、いくつかのコードは、例外をキャッチする必要があります。キャッチ例外は、より多くの計画が必要。これは議論の次のセクションです。
7.2.1キャッチ例外
例外がどこにもキャッチされていない場合、プログラムは、例外とスタックトレースの種類を考えると、メッセージコンソールを終了し、印刷します。印刷スタック・トレース・メッセージを例外をキャッチするためのGUIプログラム(アプレットおよびアプリケーション)とユーザインタフェース処理サイクルを返します。(GUIプログラムをデバッグコンソールを最小限にするのではなく、画面上に残ることが最善です。)
例外をキャッチするには、設定try/catch
ブロックを。try
ブロックの最も単純な形式は以下のとおり
try
{
code
more code
more code
}
catch (ExceptionType e)
{
handler for this type
}
場合はtry
任意のコードブロックはスローcatch
例外条項はその後、クラスを指定します
- スキップ
try
コードブロックの残りの部分を。 - プログラム実行
catch
句ハンドラのコード。
場合はtry
ブロックがコードで例外がスローされないで、プログラムはスキップされますcatch
句を。
任意のコード方式が発生した場合はcatch
指定されたタイプ以外の例外条項を、このメソッドはすぐに終了します。(私はそれが、このタイプのために提供された発信者の願うcatch
句。)
仕事でこれを実証するために、ここでいくつかの非常に一般的なデータは、コードを読んでいます。
public void read(String filename)
{
try
{
var in = new FileInputStream(filename);
int b;
while ((b = in.read()) != -1)
{
process input
}
}
catch (IOException exception)
{
exception.printStackTrace();
}
}
それに注意してくださいtry
コードのほとんどは非常に簡単です句を:ファイルの終わりが検出されるまでには、読み込み、バイトを処理します。Java APIからわかるように、read
この方法は、スローすることがありますIOException
。このケースでは、我々は全体のスキップwhile
サイクル、入力catch
句、およびスタックトレースを生成します。おもちゃのプログラムの場合は、この例外を処理するための合理的な方法であると思われます。あなたは選択肢を持っていますか?
一般的には、最良のオプションは、何もしないだけの呼び出し元に例外を渡すことです。もしread
エラー方法、そのようにread
メソッドの呼び出し側はそれについて心配!私たちは、このアプローチを採用した場合、我々はメソッドによってスローされる可能性があるという事実を公表しなければなりませんIOException
。
public void read(String filename) throws IOException
{
var in = new FileInputStream(filename);
int b;
while ((b = in.read()) != -1)
{
process input
}
}
コンパイラは厳密に施行し、覚えておいてくださいthrows
指定子を。あなたがチェック例外をスローするメソッドを呼び出した場合、あなたはそれに対処するか、またはそれを渡す必要があります。
どちらが良いですか?一般的なルールとして、あなたは例外を処理する方法を知っているものと、あなたが例外を処理する方法がわからない、それらの広がりを捉える必要があります。
例外の普及は、あなたが追加する必要があります場合はthrows
、発信者に警告するように指定し、例外が発生することがあります。
例外がスローされたものを見る方法するには、Java APIドキュメントを表示します。そして、それらを処理またはに追加するかどうかを決定throws
リスト。後者のオプション恥ずかしいものは何もありません。好ましくハンドラに向けられる能力の例外ではなく、それを抑制します。
我々は先に述べたように、この規則には例外があり、覚えておいてください。書き込みの方法は、スーパークラスのメソッドを書き換えた場合(例外をスローしない場合JComponent
にpaintComponent
)、あなたはコード方式で選択した各例外を捕捉しなければなりません。スーパークラスのメソッドサブクラスのメソッドよりも多くを追加することはできませんthrows
指定。
C ++注意
JavaとC ++でのキャッチ例外はほとんど同じです。厳密に言えば、類推
catch (Exception e) // Java
それはあります
catch (Exception& e) // C++
C ++のcatch(...)AでNO類推ありません。Javaでは、共通のスーパークラスからのすべての例外ので、そうする必要はありません。
7.2.2複数の例外を捕捉し
1であなたはできるtry
ブロックの例外タイプを複数、及び異なる方法で処理された各タイプをキャプチャします。個々のタイプのために使用するcatch
次の例では、WHERE句:
try
{
code that might throw exceptions
}
catch (FileNotFoundException e)
{
emergency action for missing files
}
catch (UnknownHostException e)
{
emergency action for unknown hosts
}
catch (IOException e)
{
emergency action for all other I/O problems
}
例外オブジェクトは、異常の性質についての情報が含まれていてもよいです。オブジェクトの詳細については、してみてください
e.getMessage()
(もしあれば)、詳細なエラーメッセージを取得、または
e.getClass().getName()
例外オブジェクトの実際の型を取得します。
Javaの7については、同じあなたはできるcatch
例外条項の複数のタイプをキャプチャします。たとえば、同じ操作が不足しているファイルや未知のホストと想定されます。そして、あなたは組み合わせることができcatch
句を。
try
{
code that might throw exceptions
}
catch (FileNotFoundException | UnknownHostException e)
{
emergency action for missing files and unknown hosts
}
catch (IOException e)
{
emergency action for all other I/O problems
}
だけでなく、サブクラスの例外タイプに属している場合にのみ、この機能をキャプチャするためにお互いを必要としています。
注意を払います
異常複数のキャプチャする場合、変数の異常暗黙最終。例えば、身体の節でない
e
異なる値を指定します。catch (FileNotFoundException | UnknownHostException e) { . . . }
注意を払います
だけでなく、複数の例外を捕捉し、コードの外観は、よりシンプルかつより効率的にします。含む共有バイトコード生成
catch
単一ブロック句。
7.2.3再送信と異常リンク
あなたはできるcatch
例外条項を投げます。あなたは、例外の種類を変更する場合、一般的に、あなたはそうすることができます。あなたは他のプログラマが使用するサブシステムを構築する場合には、使用することは、サブシステムの障害の異常型が重要である表します。例外のこのタイプの例がありますServletException
。何が間違って詳細に知られたくないことがあり、サーブレットのコードを実行し、それは確かに、サーブレットの問題を知っていただきたいと思います。
以下は、例外をキャッチして、例外を再スローするメソッドです。
try
{
access the database
}
catch (SQLException e)
{
throw new ServletException("database error: " + e.getMessage());
}
ここでは、ServletException
メッセージはテキスト異常で構成します。
しかし、新しい例外の「原因」に最善の元の例外:
try
{
access the database
}
catch (SQLException original)
{
var e = new ServletException("database error");
e.initCause(original);
throw e;
}
例外をキャッチするときは、元の例外を取得することができます。
Throwable original = caughtException.getCause();
強く、このパッケージング技術の使用をお勧めします。それはあなたが元のエラーの詳細を失うことなく、高度なサブシステムに例外をスローすることができます。
プロンプト
チェックは珍しいで投げるチェック例外を許可しない方法で発生した場合は、パッケージング技術も有用です。あなたは、ランタイムをパッケージ化され、異常と異常な選択キャプチャすることができます。
時には、あなただけの例外を記録し、変更を加えずに、それを再実行します:
try
{
access the database
}
catch (Exception e)
{
logger.log(level, message, e);
throw e;
}
Javaの7の前に、このアプローチに問題があります。プロセスコードを仮定
public void updateRecord() throws SQLException
Javaコンパイラは、参照catch
ブロックにthrow
声明し、ビューe
タイプを、および方法は、いずれかを投げることを訴えたException
だけでなく、SQLException
。今の状況は改善しています。今追跡コンパイラがe
由来try
という事実ブロック。選択されたブロックが唯一の例外である場合にはSqlException
例、およびcatch
ブロックを変更しないでくださいe
、そして宣言開閉方法がthrows SQLException
効果的です。
7.2.4 fianlly
節
コードは例外をスローする場合は、コード処理方法を停止し、残りのメソッドを終了します。この方法は、(これは知っている唯一の方法である)、いくつかの地域資源を有しており、リソースを削除しなければならない場合、これは問題です。一つの解決策は、すべての例外、クリーンアップをキャッチして、例外を再スローすることです。あなたは通常のコードと例外コードのクリーンアップリソース割り当てで2位を必要とするので、しかし、この解決策は長いです。finally
句は、この問題を解決することができます。
注意を払います
Javaの7ので、次のセクションに見られるよりエレガントな解決策があり、
try-with-resources
声明。それは概念的な基礎となっているので、我々は詳細に議論finally
メカニズムを。しかし実際には、あなたは可能よりもfinally
より頻繁に句を使用してtry-with-resource
ステートメントを。
かどうかは、例外のキャッチfinally
コードの句が実行されます。次の例では、入力ストリームは、すべてのケースで閉じます。
var in = new FileInputStream(. . .);
try
{
// 1
code that might throw exceptions
// 2
}
catch (IOException e)
{
// 3
show error message
// 4
}
finally
{
// 5
in.close();
}
// 6
実行されるのは、プログラムを見てみましょうfinally
3種類の句の可能性を。
- コードは例外をスローしません。この場合、プログラムは最初に実行される
try
全てのコードブロックを。そして、実行finally
句コード。その後、実行はに進みますfinally
句の後の最初の文。換言すれば、図2、図5及び6は、ポイントによって実行されます。 - この例では、コードは、スロー
catch
で捕捉異常な句を、IOException
。この目的を達成するために、プログラムの実行try
、すべてのコードブロックのそれは、これまで例外を発生させるまで。我々はスキップされますtry
、コードブロックの残りの部分を。次に、プログラムは、マッチング実行catch
コード句を、その後、実行finally
コード句。
場合catch
句が例外をスローしない場合、プログラムが実行されますfinally
句の後の最初の行を。このシナリオでは、点1,3,4,5及び6によって実行。
場合catch
句は例外をスローし、例外はこのメソッドの呼び出し元に戻って投げ、および点1,3および5によってのみ行われます。 - コードはすべてではないにつながった
catch
例外条項キャプチャ。ここでは、プログラムの実行try
全てのコードブロックの、例外が投げられるまで。我々はスキップされますtry
、コードブロックの残りの部分を。次に、実行するfinally
異常な、コード句とメソッドの呼び出し元に戻りました。点1及び5によってのみ行わ。
あなたは使用することができますfinally
使用せずに句をcatch
句を。たとえば、以下の点を考慮try
の文を:
InputStream in = . . .;
try
{
code that might throw exceptions
}
finally
{
in.close();
}
かかわらずtry
例外がブロックに遭遇しているかどうか、finally
句のin.close()
文が実行されます。例外が発生した場合はもちろん、それは再開始され、別のでなければなりませんcatch
キャプチャ句。
InputStream in = . . .;
try
{
try
{
code that might throw exceptions
}
finally
{
in.close();
}
}
catch (IOException e)
{
show error message
}
内部try
ブロック一つだけの責任:入力ストリームが閉じられたことを確実にします。外部try
ブロック一つだけの責任:それはエラーを報告確保します。レポート:このソリューションは、より明確かつ実用的であるだけでなくfinally
句エラー。
注意深く
finally
句が含まれているreturn
予期しない結果声明を生成することができます。仮定すると、return
声明は出てtry
中間ブロックを。メソッドが復帰する前に、実行finally
ブロック。場合はfinally
ブロックも含まれているreturn
文を、それが本来のマスク値を返します。この例を考えてみます。public static int parseInt(String s) { try { return Integer.parseInt(s); } finally { return 0; // ERROR } }
コールでは
parseInt("42")
、try
本体42を返す整数ブロックが表示されます。しかし、finally
この方法は、実際に戻る前句が実行され、リード方法は、元の戻り値を無視し、0を返します。さらに悪いはい。呼び出し考えてみましょう
parseInt("zero")
。Integer.parseInt
これは、メソッドを巻き起こしましたNumberFormatException
。そして、実行finally
句は、return
文は例外を飲み込むします!
finally
主節は、リソースをクリーンアップするために使用しました。しないfinally
制御フローを変更するreturn
(WHERE句にthrow
、break
、、continue
文)。
7.2.5 try-with-resource
ステートメント
Javaの7の場合は、モデルのコードは、便利なショートカットがあります。
open a resource
try
{
work with the resource
}
finally
{
close the resource
}
リソースが実装された場合はAutoClosable
、クラス・インターフェース。そのインターフェースは、単一のメソッドを有します
void close() throws Exception
注意を払います
別の
Closeable
インターフェイス。それはAutoCloseable
またある、サブインターフェースclose
方法は。しかし、開始のため、この方法声明IOException
。
最も単純な変形例では、try-with-resources
文の形で
try (Resource res = . . .)
{
work with res
}
ときにtry
時間ブロックが終了すると、自動的に呼び出しますres.close()
。ここではすべての単語を読んで、ファイルの典型的な例であります:
try (var in = new Scanner(
new FileInputStream("/usr/share/dict/words"), StandardCharsets.UTF_8))
{
while (in.hasNext())
System.out.println(in.next());
}
ブロックが正常か異常終了である場合、呼び出しin.close()
の使用などの方法、finally
同じブロック。
あなたは、複数のリソースを指定することができます。たとえば、
try (var in = new Scanner(
new FileInputStream("/usr/share/dict/words"), StandardCharsets
var out = new PrintWriter("out.txt", StandardCharsets.UTF_8))
{
while (in.hasNext())
out.println(in.next().toUpperCase());
}
どんなにこのコードブロックを閉じて出て行くでないとする方法。マニュアルプログラミング、そして2つの入れ子のtry / finally文の場合。
Javaの9のために、できるtry
効果的なfinal変数以前に宣言ヘッドを提供します。
public static void printAll(String[] lines, PrintWriter out)
{
try (out) { // effectively final variable
for (String line : lines)
out.println(line);
} // out.close() called here
}
ときにtry
ブロックが例外をスローし、close
この方法はまた、例外をスローしたとき、困難が生じることになります。try-with-resources
声明では、非常にエレガントなこの状況を扱います。元の例外が再開始されるclose
方法は、任意の例外がスローされていると考え、「抑制。」彼らは自動的にキャプチャして使用するaddSuppressed
元の例外にする方法を。あなたがそれらに興味がある場合は、電話にてお問い合わせくださいgetSuppressed
からメソッドをclose
抑え発現アレイ方法を生成します。
あなたは手動でプログラミングをしたくありません。あなたは、リソースをクローズする必要があるときは、使用try-with-resources
声明を。
注意を払います
try-with-resources
文自体が持っていることcatch
さえ句をfinally
句。これらは、リソースの終了後に行われます。
スタックトレース要素の7.2.6分析
スタックトレースは、保留中のすべてのメソッド呼び出しの特定の時点でプログラムの実行の一覧です。あなたはほぼ確実にJavaプログラムが終了したときに例外がクリアされないよう、彼らが表示され、スタックトレースのリストが表示されます。
呼び出すことにより、Throwable
クラスのprintStackTrace
メソッドを、あなたは、スタックトレースのテキスト記述にアクセスすることができます。
var t = new Throwable();
var out = new StringWriter();
t.printStackTrace(new PrintWriter(out));
String description = out.toString();
この方法は、より柔軟性がありStackWalker
、それが生成する、タイプStackWalker.StackFrame
の各インスタンスは、スタック・フレームを記述する、インスタンスストリーム。あなたは、この反復コールスタックフレームを使用することができます。
StackWalker walker = StackWalker.getInstance();
walker.forEach(frame -> analyze frame)
不活性ストリーム<StackWalker.StackFrame>、コールを処理するには
walker.walk(stream -> process stream)
最初のストリーム処理部の詳細の第二のボリューム。
StackWalker.StackFrame
検索の方法は、クラスファイル名とラインコードの行番号とオブジェクトクラスとメソッド名を用いて行われます。toString
フォーマットされた文字列を生成する方法は、すべての情報が含まれています。
注意を払います
ジャワ9の前に、
Throwable.getStackTrace
製造方法StackTraceElement[]
アレイを、それがStasWalk.StackFrame
情報の流れの類似例を有します。それは発呼者が数フレームのみを必要とするかもしれない場合でも、スタック全体をキャプチャして、クラス名のみ保留法(というよりも、クラスのオブジェクト)にアクセスするために利用可能であるため、コールは、低効率は、あります。
7.1スタック再帰階乗関数をリスト印刷が追跡しています。例えば、計算場合factorial(3)
、印刷出力であります
factorial(3):
stackTrace.StackTraceTest.factorial(StackTraceTest.java:20)
stackTrace.StackTraceTest.main(StackTraceTest.java:36)
factorial(2):
stackTrace.StackTraceTest.factorial(StackTraceTest.java:20)
stackTrace.StackTraceTest.factorial(StackTraceTest.java:26)
stackTrace.StackTraceTest.main(StackTraceTest.java:36)
factorial(1):
stackTrace.StackTraceTest.factorial(StackTraceTest.java:20)
stackTrace.StackTraceTest.factorial(StackTraceTest.java:26)
stackTrace.StackTraceTest.factorial(StackTraceTest.java:26)
stackTrace.StackTraceTest.main(StackTraceTest.java:36)
return 1
return 2
return 6
清单7.1スタックトレース/ StackTraceTest.java
package stackTrace;
import java.util.*;
/**
* A program that displays a trace feature of a recursive method call.
* @version 1.10 2017-12-14
* @author Cay Horstmann
*/
public class StackTraceTest
{
/**
* Computes the factorial of a number
* @param n a non-negative integer
* @return n! = 1 * 2 * . . . * n
*/
public static int factorial(int n)
{
System.out.println("factorial(" + n + "):");
var walker = StackWalker.getInstance();
walker.forEach(System.out::println);
int r;
if (n <= 1) r = 1;
else r = n * factorial(n - 1);
System.out.println("return " + r);
return r;
}
public static void main(String[] args)
{
try (var in = new Scanner(System.in))
{
System.out.print("Enter n: ");
int n = in.nextInt();
factorial(n);
}
}
}
java.lang.Trhowable
1.0
Throwable(Throwable cause)
1.4Throwable(String message, Throwable cause)
1.4
指定のreasonでThrowable
。Throwable initCause(Throwable cause)
1.4
例外がスローされた場合、このオブジェクトを設定する理由は、このオブジェクトの理由があります。リターンthis
。Throwable getCause()
1.4は、
原因が設定されていない場合、このオブジェクトの例外オブジェクトの原因のために設定されます、それはでしたnull
。StackTraceElement[] getStackTrace()
1.4
このオブジェクトトラッキングを構築するときにコールスタックを取得します。void addSuppressed(Throwable t)
7
この例外に「抑制」の例外。これは、で発生するtry-with-resources
声明、t
でclose
スローされた方法。Throwable[] getSuppressed()
7
すべての例外「を抑制するために」この例外を取得します。一般的に、これらの例外は発生しているtry-with-resources
closeメソッド文の開始。
java.lang.Exception
1.0
Exception(Throwable cause)
1.4Exception(String message, Throwable cause)
指定のreasonでException
。
java.lang.RuntimeException
1.0
RuntimeException(Throwable cause)
1.4RuntimeException(String message, Throwable cause)
1.4
指定のreasonでRuntimeException
。
java.lang.StackWalker
9
static StackWalker getInstance()
static StackWalker getInstance(StackWalker.Option option)
static StackWalker getInstance(Set<StackWalker.Option> options)
取得StackWalker
インスタンスが。オプションには、StackWalker.Option
列挙をRETAIN_CLASS_REFERENCE
、SHOW_HIDDEN_FRAMES
とSHOW_REFLECT_FRAMES
。forEach(Consumer<? super StackWalker.StackFrame> action)
walk(Function<? super Stream<StackWalker.StackFrame>,? extends T> function)
所定の関数は、ストリーム関数のスタックフレームに適用し、結果を返しています。
java.lang.StackWalker.StackFrame
9
String getFileName()
情報が利用できない場合、この要素の実行ポイントを含むソースファイルの名前を取得し、それがでしたnull
。int getLineNumber()
この要素の実行ポイント行番号を含む取得元ファイル、情報が利用できない場合は-1。String getClassName()
この要素が含まれている完全修飾名を取得する方法は、点クラスを行います。String getDeclaringClass()
クラスオブジェクトの実行ポイントを含む、この要素を得る方法。スタックウォークでない場合はRETAIN_CLASS_REFERENCE
、オプション構造、例外がスローされます。String getMethodName()
この要素法の実行ポイントを含むの名前を取得します。コンストラクタの名前です<init>
。静的初期化子名です<clinit>
。オーバーロードされたメソッドは、同じ名前を区別することはできません。boolean isNativeMethod()
この要素の実行ポイントは、ネイティブメソッドが戻る内に配置されている場合true
。String toString()
クラス名やメソッド名、ファイル名と行番号を(可能な場合)が含まれ、フォーマットされた文字列を返します。
java.lang.StackTraceElement
1.4
-
String getFileName()
情報が利用できない場合、この要素の実行ポイントを含むソースファイルの名前を取得し、それがでしたnull
。 -
int getLineNumber()
この要素の実行ポイント行番号を含む取得元ファイル、情報が利用できない場合は-1。 -
String getClassName()
完全修飾クラス名を取得すると、この要素は、ポイントを実行含まれています。 -
String getMethodName()
この要素法の実行ポイントを含むの名前を取得します。コンストラクタの名前です<init>
。静的初期化子名です<clinit>
。オーバーロードされたメソッドは、同じ名前を区別することはできません。 -
boolean isNativeMethod()
この要素の実行ポイントがネイティブメソッド内に配置されている場合は、trueを返します。
-
String toString()
クラス名やメソッド名、ファイル名と行番号を(可能な場合)が含まれ、フォーマットされた文字列を返します。