corejava11(7.2キャッチ例外)

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例外条項はその後、クラスを指定します

  1. スキップtryコードブロックの残りの部分を。
  2. プログラム実行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リスト。後者のオプション恥ずかしいものは何もありません。好ましくハンドラに向けられる能力の例外ではなく、それを抑制します。

我々は先に述べたように、この規則には例外があり、覚えておいてください。書き込みの方法は、スーパークラスのメソッドを書き換えた場合(例外をスローしない場合JComponentpaintComponent)、あなたはコード方式で選択した各例外を捕捉しなければなりません。スーパークラスのメソッドサブクラスのメソッドよりも多くを追加することはできません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

実行されるのは、プログラムを見てみましょうfinally3種類の句の可能性を。

  1. コードは例外をスローしません。この場合、プログラムは最初に実行されるtry全てのコードブロックを。そして、実行finally句コード。その後、実行はに進みますfinally句の後の最初の文。換言すれば、図2、図5及び6は、ポイントによって実行されます。
  2. この例では、コードは、スローcatchで捕捉異常な句を、IOExceptionこの目的を達成するために、プログラムの実行try、すべてのコードブロックのそれは、これまで例外を発生させるまで。我々はスキップされますtry、コードブロックの残りの部分を。次に、プログラムは、マッチング実行catchコード句を、その後、実行finallyコード句。
    場合catch句が例外をスローしない場合、プログラムが実行されますfinally句の後の最初の行を。このシナリオでは、点1,3,4,5及び6によって実行。
    場合catch句は例外をスローし、例外はこのメソッドの呼び出し元に戻って投げ、および点1,3および5によってのみ行われます。
  3. コードはすべてではないにつながった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句throwbreak、、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.4
  • Throwable(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声明、tcloseスローされた方法。
  • Throwable[] getSuppressed()7
    すべての例外「を抑制するために」この例外を取得します。一般的に、これらの例外は発生しているtry-with-resourcescloseメソッド文の開始。

java.lang.Exception 1.0

  • Exception(Throwable cause) 1.4
  • Exception(String message, Throwable cause)
    指定のreasonでException

java.lang.RuntimeException 1.0

  • RuntimeException(Throwable cause) 1.4
  • RuntimeException(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_REFERENCESHOW_HIDDEN_FRAMESSHOW_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()
    クラス名やメソッド名、ファイル名と行番号を(可能な場合)が含まれ、フォーマットされた文字列を返します。

おすすめ

転載: blog.csdn.net/nbda1121440/article/details/91496560