Java-exceptions
Java-例外
例外(または例外的なイベント)は、プログラムの実行中に発生する問題です。 *例外*が発生すると、プログラムの通常のフローが中断され、プログラム/アプリケーションが異常終了します。これは推奨されません。したがって、これらの例外は処理されます。
例外は、さまざまな理由で発生する可能性があります。 以下は、例外が発生するいくつかのシナリオです。
- ユーザーが無効なデータを入力しました。
- 開く必要があるファイルが見つかりません。
- 通信の途中でネットワーク接続が失われたか、JVMのメモリが不足しています。
これらの例外には、ユーザーエラーが原因の場合もあれば、プログラマーエラーが原因の場合もあります。
これらに基づいて、3つのカテゴリの例外があります。 Javaで例外処理がどのように機能するかを知るには、それらを理解する必要があります。
- チェック済み例外-チェック済み例外は、コンパイル時にコンパイラによってチェック(通知)される例外です。これらはコンパイル時例外とも呼ばれます。 これらの例外を単に無視することはできません。プログラマはこれらの例外を処理(処理)する必要があります。
たとえば、プログラムで FileReader クラスを使用してファイルからデータを読み取る場合、そのコンストラクターで指定されたファイルが存在しない場合、_FileNotFoundException_が発生し、コンパイラーはプログラマーに例外を処理するように求めます。
例
import java.io.File;
import java.io.FileReader;
public class FilenotFound_Demo {
public static void main(String args[]) {
File file = new File("E://file.txt");
FileReader fr = new FileReader(file);
}
}
上記のプログラムをコンパイルしようとすると、次の例外が発生します。
出力
C:\>javac FilenotFound_Demo.java
FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
FileReader fr = new FileReader(file);
^
1 error
注意-FileReaderクラスの* read()および close()*メソッドはIOExceptionをスローするため、コンパイラーはFileNotFoundExceptionとともにIOExceptionを処理するよう通知することを確認できます。
- 未チェックの例外-未チェックの例外は、実行時に発生する例外です。 これらは、*ランタイム例外*とも呼ばれます。 これには、論理エラーやAPIの不適切な使用などのプログラミングのバグが含まれます。 ランタイム例外はコンパイル時に無視されます。
たとえば、プログラムでサイズ5の配列を宣言し、配列の6 ^ th ^要素を呼び出そうとすると、_ArrayIndexOutOfBoundsExceptionexception_が発生します。
例
public class Unchecked_Demo {
public static void main(String args[]) {
int num[] = {1, 2, 3, 4};
System.out.println(num[5]);
}
}
上記のプログラムをコンパイルして実行すると、次の例外が発生します。
出力
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
- エラー-これらは例外ではなく、ユーザーまたはプログラマーの制御を超えて発生する問題です。 通常、エラーについては何も実行できないため、コード内のエラーは無視されます。 たとえば、スタックオーバーフローが発生すると、エラーが発生します。 また、コンパイル時には無視されます。
例外階層
すべての例外クラスは、java.lang.Exceptionクラスのサブタイプです。 例外クラスは、Throwableクラスのサブクラスです。 例外クラス以外に、Throwableクラスから派生したErrorという別のサブクラスがあります。
エラーは、重大な障害が発生した場合に発生する異常な状態であり、Javaプログラムでは処理されません。 エラーは、ランタイム環境によって生成されたエラーを示すために生成されます。 例:JVMはメモリ不足です。 通常、プログラムはエラーから回復できません。
Exceptionクラスには、IOExceptionクラスとRuntimeExceptionクラスの2つの主要なサブクラスがあります。
以下は、最も一般的なチェック済みおよび未チェックのリンクのリストです:/java/java_builtin_exceptions [Javaの組み込み例外]。
例外メソッド
以下は、Throwableクラスで使用できる重要なメソッドのリストです。
Sr.No. | Method & Description |
---|---|
1 |
public String getMessage() 発生した例外に関する詳細メッセージを返します。 このメッセージは、Throwableコンストラクターで初期化されます。 |
2 |
public Throwable getCause() Throwableオブジェクトで表される例外の原因を返します。 |
3 |
public String toString() getMessage()の結果と連結されたクラスの名前を返します。 |
4 |
public void printStackTrace() toString()の結果とスタックトレースをエラー出力ストリームであるSystem.errに出力します。 |
5 |
public StackTraceElement [] getStackTrace() スタックトレースの各要素を含む配列を返します。 インデックス0の要素は呼び出しスタックの一番上を表し、配列の最後の要素は呼び出しスタックの一番下のメソッドを表します。 |
6 |
public Throwable fillInStackTrace() このThrowableオブジェクトのスタックトレースを現在のスタックトレースで満たし、スタックトレース内の以前の情報に追加します。 |
例外をキャッチする
メソッドは、 try キーワードと catch キーワードの組み合わせを使用して例外をキャッチします。 try/catchブロックは、例外を生成する可能性のあるコードの周りに配置されます。 try/catchブロック内のコードは保護されたコードと呼ばれ、try/catchを使用するための構文は次のようになります-
構文
try {
//Protected code
} catch (ExceptionName e1) {
//Catch block
}
例外が発生しやすいコードは、tryブロックに配置されます。 例外が発生すると、その例外はそれに関連付けられたcatchブロックによって処理されます。 すべてのtryブロックの直後に、catchブロックまたはfinallyブロックが必要です。
catchステートメントには、キャッチしようとしている例外のタイプの宣言が含まれます。 保護されたコードで例外が発生した場合、tryに続くcatchブロックがチェックされます。 発生した例外のタイプがcatchブロックにリストされている場合、引数がメソッドパラメーターに渡されるのと同じように、例外はcatchブロックに渡されます。
例
以下は、2つの要素で宣言された配列です。 次に、コードは、例外をスローする配列の3 ^ rd ^要素にアクセスしようとします。
//File Name : ExcepTest.java
import java.io.*;
public class ExcepTest {
public static void main(String args[]) {
try {
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
これは、次の結果を生成します-
出力
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block
複数のキャッチブロック
tryブロックの後に複数のcatchブロックを続けることができます。 複数のcatchブロックの構文は次のようになります-
構文
try {
//Protected code
} catch (ExceptionType1 e1) {
//Catch block
} catch (ExceptionType2 e2) {
//Catch block
} catch (ExceptionType3 e3) {
//Catch block
}
前のステートメントは3つのcatchブロックを示していますが、1回の試行で任意の数のブロックを使用できます。 保護されたコードで例外が発生すると、リストの最初のcatchブロックに例外がスローされます。 スローされた例外のデータ型がExceptionType1と一致する場合、そこでキャッチされます。 そうでない場合、例外は2番目のcatchステートメントに渡されます。 これは、例外がキャッチされるか、すべてのキャッチを通じてフォールするまで続きます。その場合、現在のメソッドは実行を停止し、例外は呼び出しスタックの前のメソッドにスローされます。
例
複数のtry/catchステートメントの使用方法を示すコードセグメントを次に示します。
try {
file = new FileInputStream(fileName);
x = (byte) file.read();
} catch (IOException i) {
i.printStackTrace();
return -1;
} catch (FileNotFoundException f)//Not valid! {
f.printStackTrace();
return -1;
}
複数のタイプの例外をキャッチする
Java 7では、1つのcatchブロックを使用して複数の例外を処理できるため、この機能によりコードが簡素化されます。 ここにあなたがそれをする方法があります-
catch (IOException|FileNotFoundException ex) {
logger.log(ex);
throw ex;
スロー/スローキーワード
メソッドがチェック済み例外を処理しない場合、メソッドは throws キーワードを使用して宣言する必要があります。 throwsキーワードは、メソッドの署名の最後に表示されます。
*throw* キーワードを使用して、新しくインスタンス化された例外またはキャッチした例外のいずれかを例外をスローできます。
throwsキーワードとthrowキーワードの違いを理解してください。_throws_はチェック済み例外の処理を延期するために使用され、_throw_は明示的に例外を呼び出すために使用されます。
次のメソッドは、RemoteExceptionをスローすることを宣言します-
例
import java.io.*;
public class className {
public void deposit(double amount) throws RemoteException {
//Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
メソッドは、複数の例外をスローすることを宣言できます。その場合、例外はコンマで区切られたリストで宣言されます。 たとえば、次のメソッドは、RemoteExceptionとInsufficientFundsExceptionをスローすることを宣言します-
例
import java.io.*;
public class className {
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException {
//Method implementation
}
//Remainder of class definition
}
最後のブロック
finallyブロックは、tryブロックまたはcatchブロックの後に続きます。 例外の発生に関係なく、コードの最終ブロックは常に実行されます。
finallyブロックを使用すると、保護されたコードで何が起こっても、実行するクリーンアップタイプのステートメントを実行できます。
finallyブロックは、catchブロックの最後に表示され、次の構文があります-
構文
try {
//Protected code
} catch (ExceptionType1 e1) {
//Catch block
} catch (ExceptionType2 e2) {
//Catch block
} catch (ExceptionType3 e3) {
//Catch block
}finally {
//The finally block always executes.
}
例
public class ExcepTest {
public static void main(String args[]) {
int a[] = new int[2];
try {
System.out.println("Access element three :" + a[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception thrown :" + e);
}finally {
a[0] = 6;
System.out.println("First element value: " + a[0]);
System.out.println("The finally statement is executed");
}
}
}
これは、次の結果を生成します-
出力
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed
次のことに注意してください-
- catch句は、tryステートメントなしでは存在できません。
- try/catchブロックが存在するときはいつでもfinally節を持つことは必須ではありません。
- tryブロックは、catch句またはfinally句なしでは存在できません。
- try、catch、finallyブロックの間にコードを含めることはできません。
try-with-resources
通常、ストリーム、接続などのリソースを使用する場合 finallyブロックを使用して明示的に閉じる必要があります。 次のプログラムでは、 FileReader を使用してファイルからデータを読み取り、finallyブロックを使用してデータを閉じています。
例
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class ReadData_Demo {
public static void main(String args[]) {
FileReader fr = null;
try {
File file = new File("file.txt");
fr = new FileReader(file); char [] a = new char[50];
fr.read(a); //reads the content to the array
for(char c : a)
System.out.print(c); //prints the characters one by one
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fr.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
*try-with-resources* は、 *automatic resource management* とも呼ばれ、Java 7で導入された新しい例外処理メカニズムであり、try catchブロック内で使用されているリソースを自動的に閉じます。
このステートメントを使用するには、括弧内で必要なリソースを宣言するだけでよく、作成されたリソースはブロックの終わりで自動的に閉じられます。 try-with-resourcesステートメントの構文は次のとおりです。
構文
try(FileReader fr = new FileReader("file path")) {
//use the resource
} catch () {
//body of catch
}
}
以下は、try-with-resourcesステートメントを使用してファイル内のデータを読み取るプログラムです。
例
import java.io.FileReader;
import java.io.IOException;
public class Try_withDemo {
public static void main(String args[]) {
try(FileReader fr = new FileReader("E://file.txt")) {
char [] a = new char[50];
fr.read(a); //reads the contentto the array
for(char c : a)
System.out.print(c); //prints the characters one by one
} catch (IOException e) {
e.printStackTrace();
}
}
}
try-with-resourcesステートメントを使用する際には、次の点に留意してください。
- try-with-resourcesステートメントでクラスを使用するには、 AutoCloseable インターフェイスを実装し、その* close()*メソッドを実行時に自動的に呼び出す必要があります。
- try-with-resourcesステートメントで複数のクラスを宣言できます。
- try-with-resourcesステートメントのtryブロックで複数のクラスを宣言している間、これらのクラスは逆の順序で閉じられます。
- 括弧内のリソースの宣言を除いて、すべてはtryブロックの通常のtry/catchブロックと同じです。
- tryで宣言されたリソースは、tryブロックの開始直前にインスタンス化されます。
- tryブロックで宣言されたリソースは、暗黙的にfinalとして宣言されます。
ユーザー定義の例外
Javaで独自の例外を作成できます。 独自の例外クラスを作成するときは、次の点に注意してください-
- すべての例外はThrowableの子でなければなりません。
- ハンドルルールまたは宣言ルールによって自動的に適用されるチェック済み例外を作成する場合は、Exceptionクラスを拡張する必要があります。
- ランタイム例外を作成する場合は、RuntimeExceptionクラスを拡張する必要があります。
以下のように独自の例外クラスを定義できます-
class MyException extends Exception {
}
定義済みの Exception クラスを拡張して、独自の例外を作成する必要があります。 これらはチェック例外と見なされます。 次の InsufficientFundsException クラスは、Exceptionクラスを拡張するユーザー定義の例外であり、チェック例外になります。 例外クラスは他のクラスと同様に、有用なフィールドとメソッドを含んでいます。
例
//File Name InsufficientFundsException.java
import java.io.*;
public class InsufficientFundsException extends Exception {
private double amount;
public InsufficientFundsException(double amount) {
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
ユーザー定義の例外の使用を示すために、次のCheckingAccountクラスには、InsufficientFundsExceptionをスローするwithdraw()メソッドが含まれています。
//File Name CheckingAccount.java
import java.io.*;
public class CheckingAccount {
private double balance;
private int number;
public CheckingAccount(int number) {
this.number = number;
}
public void deposit(double amount) {
balance += amount;
}
public void withdraw(double amount) throws InsufficientFundsException {
if(amount <= balance) {
balance -= amount;
}else {
double needs = amount - balance;
throw new InsufficientFundsException(needs);
}
}
public double getBalance() {
return balance;
}
public int getNumber() {
return number;
}
}
次のBankDemoプログラムは、CheckingAccountのdeposit()およびwithdraw()メソッドの呼び出しを示しています。
//File Name BankDemo.java
public class BankDemo {
public static void main(String [] args) {
CheckingAccount c = new CheckingAccount(101);
System.out.println("Depositing $500...");
c.deposit(500.00);
try {
System.out.println("\nWithdrawing $100...");
c.withdraw(100.00);
System.out.println("\nWithdrawing $600...");
c.withdraw(600.00);
} catch (InsufficientFundsException e) {
System.out.println("Sorry, but you are short $" + e.getAmount());
e.printStackTrace();
}
}
}
上記の3つのファイルをすべてコンパイルし、BankDemoを実行します。 これは、次の結果を生成します-
出力
Depositing $500...
Withdrawing $100...
Withdrawing $600...
Sorry, but you are short $200.0
InsufficientFundsException
at CheckingAccount.withdraw(CheckingAccount.java:25)
at BankDemo.main(BankDemo.java:13)
一般的な例外
Javaでは、例外とエラーの2つのカテゴリを定義できます。
- * JVM例外*-これらは、JVMによって排他的または論理的にスローされる例外/エラーです。 例:NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException。
- プログラムの例外-これらの例外は、アプリケーションまたはAPIプログラマーによって明示的にスローされます。 例:IllegalArgumentException、IllegalStateException。