Javaは、Java例外処理として知られる例外シナリオを処理するための堅牢でオブジェクト指向のアプローチを提供します。以前、私はJavaにおける例外処理についての長い投稿を書きました。今日は、面接で役立ついくつかの重要なJava例外の質問と回答をリストアップしています。
- Javaでの例外とは何ですか?
- Javaでの例外処理のキーワードは何ですか?
- Java例外の階層を説明してください。
- Javaの例外クラスの重要なメソッドは何ですか?
- Java 7のARM機能とマルチキャッチブロックを説明してください。
- Javaでのチェック済み例外と未チェック例外の違いは何ですか?
- Javaでのthrowキーワードとthrowsキーワードの違いは何ですか?
- Javaでカスタム例外を作成する方法は?
- JavaでのOutOfMemoryErrorとは何ですか?
- 「スレッドmainでの例外」を引き起こすさまざまなシナリオは何ですか?
- Javaでfinal、finally、finalizeの違いは何ですか?
- メインメソッドで例外がスローされるとどうなりますか?
- 空のキャッチブロックを持つことはできますか?
- Javaの例外処理のベストプラクティスを提供してください。
- 以下のプログラムにはどのような問題があり、どのように修正すればよいですか?
1. Javaにおける例外とは何ですか?
例外は、プログラムの実行中に発生し、通常のフローを妨げるエラーイベントです。例外は、ユーザーによって入力された間違ったデータ、ハードウェアの障害、ネットワーク接続の障害など、さまざまな状況から発生する可能性があります。Javaステートメントの実行中にエラーが発生すると、例外オブジェクトが作成され、JREは例外ハンドラを見つけて例外を処理しようとします。適切な例外ハンドラが見つかると、例外オブジェクトはハンドラコードに渡されて例外を処理し、例外を「キャッチ」します。ハンドラが見つからない場合、アプリケーションは例外を実行環境にスローし、JREはプログラムを終了します。例外処理フレームワークはランタイムエラーのみを処理するために使用されます。コンパイル時エラーは例外処理フレームワークでは処理されません。
2. Javaでの例外処理キーワードは何ですか?
Javaの例外処理には4つのキーワードが使用されます。
- throw: 時々、明示的に例外オブジェクトを作成し、それを投げてプログラムの通常の処理を停止したい場合があります。 throw キーワードは、例外を実行時に投げて処理させるために使用されます。
- throws: メソッドでチェックされる例外を投げており、それを処理していない場合、メソッドシグネチャに throws キーワードを使用して、呼び出し元のプログラムがメソッドで投げられる可能性のある例外を知る必要があります。 呼び出し元のメソッドはこれらの例外を処理するか、 throws キーワードを使用してその呼び出し元のメソッドに伝播させることができます。 throws 句では複数の例外を指定することができ、main() メソッドでも使用できます。
- try-catch: コードでの例外処理には try-catch ブロックを使用します。 try はブロックの開始であり、catch は例外を処理するための try ブロックの末尾にあります。 try ブロックには複数の catch ブロックを持たせることができ、try-catch ブロックをネストさせることもできます。 catch ブロックには Exception 型のパラメータが必要です。
- 最終的に: finallyブロックはオプションで、try-catchブロックとのみ使用できます。例外が実行プロセスを停止するため、閉じられないリソースがある可能性があるため、finallyブロックを使用できます。finallyブロックは常に実行され、例外が発生しても発生しなくても実行されます。
3. Javaの例外階層を説明してください。
Javaの例外は階層的で、継承が異なる種類の例外を分類するために使用されます。 Throwable
はJavaの例外階層の親クラスであり、Error
とException
の2つの子オブジェクトがあります。例外はさらに、チェックされた例外と実行時例外に分かれています。 エラーは、アプリケーションの範囲外で発生する特殊なシナリオであり、それらを予測して回復することはできません。たとえば、ハードウェアの障害、JVMのクラッシュ、またはメモリ不足などです。 チェックされた例外は、プログラムで予測でき、回復を試みることができる特殊なシナリオです。たとえば、FileNotFoundExceptionです。この例外をキャッチして、ユーザーに有用なメッセージを提供し、デバッグ目的で適切にログを取る必要があります。 Exception
はすべてのチェックされた例外の親クラスです。 実行時例外は、悪いプログラミングによって引き起こされます。たとえば、配列から要素を取得しようとすることです。要素を取得する前に配列の長さを確認する必要があります。そうしないと、実行時にArrayIndexOutOfBoundException
がスローされる可能性があります。 RuntimeException
はすべての実行時例外の親クラスです。
4. JavaのExceptionクラスの重要なメソッドは何ですか?
Exceptionおよびそのすべてのサブクラスには、特定のメソッドが提供されておらず、すべてのメソッドが基本クラスThrowableで定義されています。
- String getMessage() – このメソッドは、ThrowableのメッセージStringを返し、例外を作成する際にメッセージを提供することができます。
- String getLocalizedMessage() – このメソッドは、サブクラスがロケール固有のメッセージを呼び出しプログラムに提供するためにオーバーライドできるように提供されています。 Throwableクラスのこのメソッドの実装では、単純に
getMessage()
メソッドを使用して例外メッセージを返します。 - synchronized Throwable getCause() – このメソッドは、例外の原因を返し、原因が不明な場合はnullを返します。
- String toString() – このメソッドは、Throwableに関する情報を文字列形式で返します。返される文字列には、Throwableクラスの名前とローカライズされたメッセージが含まれます。
- void printStackTrace() – このメソッドは、スタックトレース情報を標準エラーストリームに出力します。このメソッドはオーバーロードされており、スタックトレース情報をファイルまたはストリームに書き込むためにPrintStreamまたはPrintWriterを引数として渡すことができます。
Java 7 ARM機能とマルチキャッチブロックを説明しますか?
1つのtryブロックで多くの例外をキャッチしている場合、catchブロックのコードが非常に見苦しく、エラーをログに記録するための冗長なコードでほとんど構成されていることに気付くでしょう。このようなことを考慮して、Java 7の機能の1つはマルチキャッチブロックで、1つのcatchブロックで複数の例外をキャッチできます。この機能を備えたcatchブロックは次のようになります:
catch(IOException | SQLException | Exception ex){
logger.error(ex);
throw new MyException(ex.getMessage());
}
ほとんどの場合、finallyブロックはリソースを閉じるためだけに使用されますが、リソースを閉じるのを忘れてしまうことがあり、リソースが枯渇したときに実行時例外が発生します。これらの例外はデバッグが難しく、そのタイプのリソースを使用している場所ごとに確認する必要があります。したがって、Java 7の改善策の1つはtry-with-resourcesです。ここでは、tryステートメント自体でリソースを作成し、try-catchブロック内でそれを使用できます。try-catchブロックから抜けると、実行環境がこれらのリソースを自動的に閉じます。この改善されたtry-catchブロックのサンプルは次のとおりです:
try (MyResource mr = new MyResource()) {
System.out.println("MyResource created in try-with-resources");
} catch (Exception e) {
e.printStackTrace();
}
詳細については、Java 7 ARMを参照してください。
6. JavaにおけるCheckedとUncheckedの例外の違いは何ですか?
- Checked Exceptionsは、try-catchブロックを使用してコードで処理するか、そうでなければメソッドがthrowsキーワードを使用して、メソッドからスローされる可能性のあるチェックされた例外について呼び出し元に知らせる必要があります。Unchecked Exceptionsはプログラムで処理する必要はなく、メソッドのthrows句にそれらを記述する必要もありません。
Exception
は、すべてのチェックされた例外のスーパークラスであり、RuntimeException
はすべての未チェック例外のスーパークラスです。RuntimeExceptionはExceptionの子クラスであることに注意してください。- チェックされた例外は、コードで処理する必要があるエラーのシナリオであり、そうでないとコンパイル時エラーが発生します。例えば、FileReaderを使用してファイルを読み取ると、
FileNotFoundException
がスローされ、それをtry-catchブロックでキャッチするか、呼び出し元のメソッドに再度スローする必要があります。未チェックの例外は、主に不適切なプログラミングによって引き起こされます。例えば、オブジェクト参照でメソッドを呼び出す際に、それがnullでないことを確認しない場合のNullPointerExceptionなどです。例えば、文字列からすべての母音を削除するメソッドを作成できますが、呼び出し元はnull文字列を渡さないようにする責任があります。このようなシナリオを処理するためにメソッドを変更することができますが、理想的には呼び出し元がこれに注意するべきです。
7. Javaにおけるthrowとthrowsキーワードの違いは何ですか?
throwsキーワードは、メソッドのシグネチャと共に使用され、メソッドがスローする可能性のある例外を宣言するために使用されます。一方、throwキーワードはプログラムのフローを中断し、例外オブジェクトをランタイムに渡して処理させるために使用されます。
8. Javaでカスタム例外をどのように書きますか?
カスタム例外クラスを作成するには、Exceptionクラスまたはそのサブクラスを拡張します。カスタム例外クラスには、エラーコードやその他の例外関連情報を例外ハンドラに渡すために使用できる独自の変数やメソッドを持たせることができます。カスタム例外の単純な例を以下に示します。
package com.journaldev.exceptions;
import java.io.IOException;
public class MyException extends IOException {
private static final long serialVersionUID = 4664456874499611218L;
private String errorCode="Unknown_Exception";
public MyException(String message, String errorCode){
super(message);
this.errorCode=errorCode;
}
public String getErrorCode(){
return this.errorCode;
}
}
9. JavaにおけるOutOfMemoryErrorとは何ですか?
JavaのOutOfMemoryErrorはjava.lang.VirtualMachineErrorのサブクラスであり、JVMがヒープメモリーを使い果たしたときにスローされます。このエラーは、Javaオプションを使用してJavaアプリケーションにより多くのメモリを提供することで修正できます。 $>java MyProgram -Xms1024m -Xmx1024m -XX:PermSize=64M -XX:MaxPermSize=256m
10. “Exception in thread main”が発生するさまざまなシナリオは何ですか?
一般的なメインスレッドの例外シナリオのいくつかは次のとおりです:
- Exception in thread main java.lang.UnsupportedClassVersionError: この例外は、Javaクラスが別のJDKバージョンからコンパイルされており、別のJavaバージョンから実行しようとしているときに発生します。
- Exception in thread main java.lang.NoClassDefFoundError: この例外には2つのバリアントがあります。最初のバリアントは、.class拡張子を使用してクラスの完全な名前を提供する場合です。2番目のシナリオは、クラスが見つからない場合です。
- Exception in thread main java.lang.NoSuchMethodError: main: この例外は、mainメソッドを持たないクラスを実行しようとした場合に発生します。
- メインスレッドでの例外:メインメソッドから例外がスローされると、コンソールに例外が表示されます。最初の部分は、メインメソッドから例外がスローされていることを説明し、次に例外クラス名が印刷され、コロンの後に例外メッセージが印刷されます。
これについて詳しくは、Javaメインスレッドの例外を参照してください。
11. Javaでfinal、finally、およびfinalizeの違いは何ですか?
finalおよびfinallyはJavaのキーワードですが、finalizeはメソッドです。finalキーワードはクラス変数に使用でき、それらが再割り当てされないようにし、クラスにクラス拡張を避けるために使用でき、サブクラスによるオーバーライドを避けるためにメソッドと一緒に使用できます。finallyキーワードは、try-catchブロックと一緒に使用され、例外が発生しても常に実行されるステートメントを提供するために使用されます。通常、finallyはリソースを閉じるために使用されます。finalize()メソッドは、オブジェクトが破棄される前にガベージコレクタによって実行されます。これは、すべてのグローバルリソースが閉じられていることを確認するための優れた方法です。この3つのうち、finallyのみがJava例外処理に関連しています。
12. メインメソッドで例外がスローされた場合、何が起こりますか?
メイン()メソッドで例外がスローされると、Javaランタイムはプログラムを終了し、例外メッセージとスタックトレースをシステムコンソールに出力します。
13. 空のcatchブロックを持つことはできますか?
空のcatchブロックを持つことはできますが、これは悪いプログラミングの例です。空のcatchブロックを持つべきではありません。なぜなら、そのブロックで例外がキャッチされると、例外に関する情報がなくなり、デバッグが非常に困難になる可能性があるからです。少なくともログステートメントがある必要があります。例外の詳細をコンソールまたはログファイルに記録するための
14. Java例外処理のベストプラクティスをいくつか提供してください。
Java例外処理に関連するいくつかのベストプラクティスは次のとおりです:
- デバッグを容易にするために特定の例外を使用します。
- プログラムで例外を早期にスローします(Fail-Fast)。
- プログラムの最後で例外をキャッチし、呼び出し元に例外処理を任せます。
- Java 7のARM機能を使用してリソースが閉じられることを確認するか、finallyブロックを使用して適切に閉じます。
- デバッグ目的で常に例外メッセージをログに記録します。
- クリーンなクローズのためにマルチキャッチブロックを使用します。
- カスタム例外を使用して、アプリケーションAPIから単一のタイプの例外をスローします。
- 命名規則に従い、常にExceptionで終わります。
- Javaドキュメントでメソッドがスローする例外を文書化するには、@throwsを使用します。
- 例外はコストがかかるため、意味がある場合にのみスローします。それ以外の場合は、例外をキャッチしてnullまたは空の応答を提供できます。
詳細については、Java例外処理のベストプラクティスで詳細を読んでください。
15. 以下のプログラムの問題点は何であり、どのように修正しますか?
このセクションでは、Java例外に関連するいくつかのプログラミングの質問を見ていきます。
-
以下のプログラムに問題がありますか?
package com.journaldev.exceptions; import java.io.FileNotFoundException; import java.io.IOException; public class TestException { public static void main(String[] args) { try { testExceptions(); } catch (FileNotFoundException | IOException e) { e.printStackTrace(); } } public static void testExceptions() throws IOException, FileNotFoundException{ } }
上記のプログラムはコンパイルされず、エラーメッセージが表示されます。「The exception FileNotFoundException is already caught by the alternative IOException」というエラーが出ます。これは、FileNotFoundExceptionがIOExceptionのサブクラスであるためです。この問題を解決する方法は2つあります。最初の方法は、両方の例外に対して単一のキャッチブロックを使用することです。
try { testExceptions(); }catch(FileNotFoundException e){ e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); }
別の方法は、マルチキャッチブロックからFileNotFoundExceptionを削除することです。
try { testExceptions(); }catch (IOException e) { e.printStackTrace(); }
これらのアプローチのどちらかを選択できます。キャッチブロックコードに基づいてください。
-
以下のプログラムの問題は何ですか?
package com.journaldev.exceptions; import java.io.FileNotFoundException; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException1 { public static void main(String[] args) { try { go(); } catch (IOException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); } } public static void go() throws IOException, JAXBException, FileNotFoundException{ } }
FileNotFoundExceptionはIOExceptionのサブクラスであるため、FileNotFoundExceptionのキャッチブロックは到達不能であり、エラーメッセージ「FileNotFoundExceptionの到達不能なキャッチブロック。IOExceptionのキャッチブロックで既に処理されています」としてエラーが発生します。この問題を解決するには、キャッチブロックの順序を修正する必要があります。
try { go(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); }
JAXBExceptionはIOExceptionやFileNotFoundExceptionと関係がなく、上記のキャッチブロック階層のどこにでも配置できることに注意してください。
-
以下のプログラムにはどのような問題がありますか?
package com.journaldev.exceptions; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException2 { public static void main(String[] args) { try { foo(); } catch (IOException e) { e.printStackTrace(); }catch(JAXBException e){ e.printStackTrace(); }catch(NullPointerException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } } public static void foo() throws IOException{ } }
プログラムはコンパイルされません。JAXBExceptionはチェックされる例外であり、foo()メソッドはこの例外をスローする必要があります。tryステートメントの本体からJAXBExceptionはスローされないため、「JAXBExceptionの到達不能なcatchブロックです。この例外はtryステートメントの本体からスローされません」というエラーメッセージが表示されます。この問題を解決するには、JAXBExceptionのcatchブロックを削除する必要があります。NullPointerExceptionをキャッチすることは有効ですが、これは非チェック例外です。
-
以下のプログラムの問題点は何ですか?
package com.journaldev.exceptions; public class TestException3 { public static void main(String[] args) { try{ bar(); }catch(NullPointerException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } foo(); } public static void bar(){ } public static void foo() throws NullPointerException{ } }
これはトリックの質問で、コードに問題はありません。コンパイルは成功します。例外またはチェックされていない例外がスローされなくても、常に例外や非チェック例外をキャッチできます。同様に、メソッド(foo)がthrows句で非チェック例外を宣言している場合、その例外をプログラムで処理する必要はありません。
-
以下のプログラムにはどのような問題がありますか?
package com.journaldev.exceptions; import java.io.IOException; public class TestException4 { public void start() throws IOException{ } public void foo() throws NullPointerException{ } } class TestException5 extends TestException4{ public void start() throws Exception{ } public void foo() throws RuntimeException{ } }
上記のプログラムはコンパイルされません。サブクラスのstart()メソッドのシグネチャがスーパークラスと同じではないためです。この問題を修正するには、サブクラスのメソッドのthrows句を削除するか、以下に示すようにサブクラスのメソッドのシグネチャをスーパークラスとまったく同じに変更できます。
@Override public void start(){ }
-
以下のプログラムの問題は何ですか?
package com.journaldev.exceptions; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException6 { public static void main(String[] args) { try { foo(); } catch (IOException | JAXBException e) { e = new Exception(""); e.printStackTrace(); }catch(Exception e){ e = new Exception(""); e.printStackTrace(); } } public static void foo() throws IOException, JAXBException{ } }
上記のプログラムはコンパイルされません。マルチキャッチブロック内の例外オブジェクトが final であり、その値を変更できないためです。”The parameter e of a multi-catch block cannot be assigned” というコンパイル時エラーが発生します。このエラーを解決するには、”e” への新しい例外オブジェクトの代入を削除する必要があります。詳細は Java 7 multi-catch block を参照してください。
これでJava例外に関するインタビューの質問はすべてです。お楽しみいただければ幸いです。将来的にリストにさらに追加する予定ですので、お気に入りに追加してください。
Source:
https://www.digitalocean.com/community/tutorials/java-exception-interview-questions-and-answers