1. 例外の種類

すべての例外は 4 つのタイプに分類され、実際には相互に継承するクラスです。

Throwableクラス

すべての例外の基本クラスはThrowableクラスです。このThrowableクラスには、現在の呼び出しスタック (現在のメソッドのスタック トレース) を配列に書き込むコードが含まれています。スタック トレースとは何かについては、少し後で学びます。

throw演算子は、クラスから派生したオブジェクトのみを受け入れることができますThrowable理論的には のようなコードを書くこともできますがthrow new Throwable();、通常は誰もこれを行いません。このクラスの主な目的はThrowable、すべての例外に対して単一の親クラスを持つことです。

Errorクラス

次の例外クラスはError、クラスを直接継承するクラスですThrowable重大な問題が発生した場合、 Java マシンはErrorクラス (およびその子孫)のオブジェクトを作成します。たとえば、ハードウェアの故障、メモリ不足などです。

通常、プログラマーとして、このようなエラー (エラーがスローされるべき種類) がプログラム内で発生した状況では、何もすることができません。これらのエラーは深刻すぎるためです。Errorできることは、プログラムがクラッシュしていることをユーザーに通知するか、エラーに関する既知の情報をすべてプログラム ログに書き込むことだけです。

Exceptionクラス

およびクラスは、多くのメソッドの操作中に発生する一般的なエラーに対応しますExceptionスローされた各例外の目標は、それを適切に処理する方法を知っているブロックによってキャッチされることです。RuntimeExceptioncatch

メソッドが何らかの理由で作業を完了できない場合、適切なタイプの例外をスローして呼び出し側メソッドに直ちに通知する必要があります。

つまり、変数が に等しい場合null、メソッドは をスローしますNullPointerException。不正な引数がメソッドに渡された場合、メソッドは をスローしますInvalidArgumentException。メソッドが誤ってゼロで除算した場合、 がスローされますArithmeticException

RuntimeExceptionクラス

RuntimeExceptionsは のサブセットですExceptionsRuntimeExceptionこれは通常の例外 ( ) の軽量バージョンであるとさえ言えますException。そのような例外に課される要件と制限は少なくなります。

Exceptionとの違いについては後で学びますRuntimeException


2. Throws:チェックされた例外

すべての Java 例外は、「チェック済み」と「チェックなし」の2 つのカテゴリに分類されます。

RuntimeExceptionまたはを継承するすべての例外は、未チェック例外Errorとみなされます。 その他はすべてチェック例外です。

重要!

チェック例外が導入されてから 20 年が経過しましたが、ほとんどすべての Java プログラマーがこれをバグだと考えています。一般的な最新のフレームワークでは、すべての例外の 95% がチェックされていません。Java をほぼ正確にコピーした C# 言語は、チェック例外を追加しませんでした。

チェック済み例外とチェックなし例外の主な違いは何ですか?

チェック例外には追加の要件が課されます。大まかに言うと、これらは次のとおりです。

要件1

メソッドがチェック例外をスローする場合、そのシグネチャで例外のタイプを示す必要がありますそうすることで、それを呼び出すすべてのメソッドは、この「意味のある例外」がその中で発生する可能性があることを認識します。

キーワードの後のメソッド パラメータの後にチェック例外を示します(キーワードを誤って使用しないでください)。次のようになります。throwsthrow

type method (parameters) throws exception

例:

チェックされた例外 未チェックの例外
public void calculate(int n) throws Exception
{
   if (n == 0)
      throw new Exception("n is null!");
}
public void calculate(n)
{
   if (n == 0)
      throw new RuntimeException("n is null!");
}

右側の例では、コードは未チェックの例外をスローします。追加のアクションは必要ありません。 左側の例では、メソッドがチェック済み例外をスローするため、throwsキーワードが例外のタイプとともにメソッド シグネチャに追加されます。

メソッドが複数のチェック例外をスローすることを予期している場合は、それらすべてをthrowsキーワードの後に​​カンマで区切って指定する必要があります。順序は重要ではありません。例:

public void calculate(int n) throws Exception, IOException
{
   if (n == 0)
      throw new Exception("n is null!");
   if (n == 1)
      throw new IOException("n is 1");
}

要件2

シグネチャ内にチェック例外が含まれるメソッドを呼び出す場合、例外がスローされるという事実を無視することはできません。

catchこのような例外をすべてキャッチするには、例外ごとにブロックを追加するか、メソッドの句にブロックを追加する必要があります。throws

それはまるで、「これらの例外は非常に重要なので、必ずキャッチしなければなりません。そして、それらの処理方法がわからない場合、メソッドを呼び出す可能性のある人には、そのような例外が発生する可能性があることを通知する必要があります。」と言っているかのようです。

例:

人間が住む世界を作成するメソッドを作成していると想像してください。初期人数は引数として渡されます。したがって、人数が少なすぎる場合は例外を追加する必要があります。

地球を創る ノート
public void createWorld(int n) throws EmptyWorldException, LonelyWorldException
{
   if (n == 0)
      throw new EmptyWorldException("There are no people!");
   if (n == 1)
      throw new LonelyWorldException ("There aren't enough people!");
   System.out.println("A wonderful world was created. Population: " + n);
}
このメソッドは、次の 2 つのチェック例外をスローする可能性があります。

  • EmptyWorldException
  • LonelyWorldException

このメソッド呼び出しは 3 つの方法で処理できます。

1. 例外をキャッチしない

これは、メソッドが状況を適切に処理する方法を知らない場合に最も頻繁に行われます。

コード ノート
public void createPopulatedWorld(int population)
throws EmptyWorldException, LonelyWorldException
{
   createWorld(population);
}
呼び出し側メソッドは例外をキャッチしないため、例外を他のメソッドに通知する必要があります。例外を独自のthrows句に追加します。

2. いくつかの例外をキャッチする

対応できるエラーには対応いたします。しかし、理解できないものは、呼び出し側のメソッドにスローします。これを行うには、throws 節に名前を追加する必要があります。

コード ノート
public void createNonEmptyWorld(int population)
throws EmptyWorldException
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
}
呼び出し元は、チェックされた例外を 1 つだけキャッチします — LonelyWorldException。他の例外は、その署名にthrowsキーワードの後に​​それを示すように追加する必要があります。

3. すべての例外をキャッチする

メソッドが呼び出し側メソッドに例外をスローしない場合、呼び出し側メソッドは常にすべてが正常に動作したと確信します。そして、例外的な状況を修正するための措置を講じることができなくなります。

コード ノート
public void createAnyWorld(int population)
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
   catch (EmptyWorldException e)
   {
      e.printStackTrace();
   }
}
すべての例外はこのメソッドでキャッチされます。電話をかけてきた人は、すべてがうまくいったと確信するでしょう。


3. 複数の例外をキャッチする

プログラマーはコードを複製することを非常に嫌います。彼らは、対応する開発原則「DRY : Don't Reply Yourself」さえも考案しました。ただし、例外を処理する場合、1 つのブロックの後に同じコードを持つ複数のブロックが続くことがよくあります。trycatch

catchまたは、同じコードを持つ3 つのブロックと、別の同じコードを持つ別の 2 つのブロックが存在する可能性がありますcatch。これは、プロジェクトが責任を持って例外を処理する場合の標準的な状況です。

バージョン 7 以降、Java 言語には、単一のcatchブロックで複数のタイプの例外を指定する機能が追加されました。おおよそ次のようになります。

try
{
   // Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
   // Exception handling code
}

catchブロックは必要な数だけ持つことができます。ただし、単一のcatchブロックで、相互に継承する例外を指定することはできません。つまり、クラスは を継承するため、catch ( Exception| RuntimeExceptione)を記述することはできません。RuntimeExceptionException