1概要

例外は、すべてのJava開発者になじみのある重要なトピックです。この記事では、インタビュー中にポップアップする可能性があるいくつかの質問に対する回答を示します。


2質問


Q1. 例外とは何ですか?

例外は、プログラムの実行中に発生し、プログラムの命令の正常な流れを妨げる異常なイベントです。


Q2.

throw

および

throws

キーワードの目的は何ですか?


throws

キーワードは、メソッドが実行中に例外を発生させることを指定するために使用されます。メソッドを呼び出すときに明示的な例外処理を強制します。

public void simpleMethod() throws Exception {
   //...
}


throw

キーワードを使用すると、例外オブジェクトをスローしてプログラムの通常の流れを中断することができます。これはプログラムが与えられた条件を満たすことができないときに最も一般的に使われます:

if (task.isTooComplicated()) {
    throw new TooComplicatedException("The task is too complicated");
}


Q3. どうすれば例外を処理できますか?


try-catch-finally

ステートメントを使用して:

try {
   //...
} catch (ExceptionType1 ex) {
   //...
} catch (ExceptionType2 ex) {
   //...
} finally {
   //...
}

例外が発生する可能性のあるコードブロックは、

try

ブロックで囲まれています。このブロックは「保護」または「保護」コードとも呼ばれます。

例外が発生した場合は、スローされている例外に一致する

catch

ブロックが実行されます。それ以外の場合は、すべての

catch

ブロックが無視されます。


finally

ブロックは、例外がスローされたかどうかにかかわらず、常に

try

ブロックの終了後に実行されます。


Q4. どうすれば複数の例外をキャッチできますか?

コードブロック内で複数の例外を処理する方法は3つあります。

1つ目は、スローされているすべての例外タイプを処理できる

catch

ブロックを使用することです。

try {
   //...
} catch (Exception ex) {
   //...
}

推奨される方法はできるだけ正確な例外ハンドラを使用することです。

幅が広すぎる例外ハンドラを使用すると、コードのエラーが発生しやすくなり、予期しない例外が捕捉され、プログラムで予期しない動作が発生する可能性があります。

2番目の方法は複数のcatchブロックを実装することです。

try {
   //...
} catch (FileNotFoundException ex) {
   //...
} catch (EOFException ex) {
   //...
}

例外に継承関係がある場合は、注意してください。子タイプは最初に来て、親タイプは後に来なければなりません。これに失敗すると、コンパイルエラーになります。

3番目はマルチキャッチブロックを使用することです。

try {
   //...
} catch (FileNotFoundException | EOFException ex) {
   //...
}

この機能は、Java 7で初めて導入されました。コードの重複を減らし、保守を容易にします。


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

チェック済み例外は、

try-catch

ブロック内で処理するか、

throws

節で宣言する必要があります。未チェックの例外は処理も宣言もする必要はありません。

チェック済み例外とチェックなし例外は、それぞれコンパイル時例外と実行時例外とも呼ばれます。


Error



RuntimeException

、およびそれらのサブクラスで示されるものを除き、すべての例外は検査済み例外です。


Q6. 例外とエラーの違いは何ですか?

例外は、回復が可能な状態を表すイベントです。エラーは、通常は回復が不可能な外部状況を表します。

JVMによってスローされるすべてのエラーは、

Error

またはそのサブクラスの1つのインスタンスです。より一般的なものには、次のものが含まれますが、これらに限定されません。


  • OutOfMemoryError

    – JVMがそれ以上オブジェクトを割り当てられない場合にスローされます

メモリ不足のため、ガベージコレクタが作成できませんでした。
もっと利用できる
**

StackOverflowError

– スレッドのスタックスペースが

通常はアプリケーションの再帰が深すぎるため
**

ExceptionInInitializerError

– 予期しない例外を通知します

静的初期化子の評価中に発生しました
**

NoClassDefFoundError

– クラスローダがロードしようとしたときにスローされます

クラスの定義でそれを見つけることができませんでした。
必要な

class

ファイルがクラスパスに見つかりませんでした
**

UnsupportedClassVersionError

– JVMが読み込もうとしたときに発生します


class

ファイル。ファイル内のバージョンがサポートされていないと判断します。通常、ファイルは新しいバージョンのJavaで生成されたため


try

ステートメントを使用してエラーを処理することはできますが、エラーがスローされた後にプログラムが確実に何かを実行できるという保証はないため、これはお勧めできません。


Q7. 次のコードブロックを実行すると、どのような例外がスローされますか?

Integer[][]ints = { { 1, 2, 3 }, { null }, { 7, 8, 9 } };
System.out.println("value = " + ints[1][1].intValue());

配列の長さを超える位置にアクセスしようとしているため、

ArrayIndexOutOfBoundsException

がスローされます。


Q8. 例外連鎖とは何ですか?

別の例外に応答して例外がスローされたときに発生します。

これにより、発生した問題の完全な履歴を見つけることができます。

try {
    task.readConfigFile();
} catch (FileNotFoundException ex) {
    throw new TaskException("Could not perform task", ex);
}


Q9. スタックトレースとは何ですか?また、それは例外とどのように関連していますか?

スタックトレースは、アプリケーションの開始から例外が発生した時点までに呼び出されたクラスとメソッドの名前を提供します。

アプリケーションのどこで例外がスローされたのか、およびその原因となった元の原因を正確に特定できるため、非常に便利なデバッグツールです。


Q10. なぜあなたは例外をサブクラス化したいのですか?

例外タイプがすでにJavaプラットフォームに存在するもので表されていない場合、またはそれをより正確な方法で処理するためにクライアントコードにさらに情報を提供する必要がある場合は、カスタム例外を作成する必要があります。

カスタム例外をチェックするかどうかは、完全にビジネスケースに依存します。ただし、経験則として。自分の例外を使用しているコードがそれからの回復を期待できる場合は、チェックされた例外を作成します。

また、スローしたいサブクラスに密接に関連する最も具体的な

Exception

サブクラスから継承する必要があります。そのようなクラスがない場合は、

Exception

を親として選択してください。


Q11. 例外の利点は何ですか?

伝統的なエラー検出と処理技術はしばしばスパゲッティコードを維持するのを難しくしそして読むのを困難にする。ただし、例外により、予期しないことが発生した場合の対処方法の詳細からアプリケーションのコアロジックを切り離すことができます。

また、JVMはコールスタックを逆方向に検索して、特定の例外の処理に関心のあるメソッドを見つけます。追加のコードを書かずにエラーをコールスタックに伝播させることができます。

また、プログラム内でスローされる例外はすべてオブジェクトなので、クラス階層に基づいてグループ化または分類することができます。これにより、

catch

ブロックで例外のスーパークラスを指定することで、単一の例外ハンドラでグループの例外をキャッチできます。

==== * Q12。ラムダ式の本体内で例外をスローできますか?**

Javaによってすでに提供されている標準機能インターフェースを使用する場合、標準機能インターフェースにはメソッドシグニチャーに「throws」節がないため、未チェックの例外のみをスローできます。

List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);
integers.forEach(i -> {
    if (i == 0) {
        throw new IllegalArgumentException("Zero not allowed");
    }
    System.out.println(Math.PI/i);
});

ただし、カスタム機能インターフェースを使用している場合は、チェック済み例外をスローすることが可能です。

@FunctionalInterface
public static interface CheckedFunction<T> {
    void apply(T t) throws Exception;
}

public void processTasks(
  List<Task> taks, CheckedFunction<Task> checkedFunction) {
    for (Task task : taks) {
        try {
            checkedFunction.apply(task);
        } catch (Exception e) {
           //...
        }
    }
}

processTasks(taskList, t -> {
   //...
    throw new Exception("Something happened");
});

==== * Q13。例外をスローするメソッドをオーバーライドするときに従うべき規則は何ですか?**

いくつかの規則は、継承の文脈で例外をどのように宣言しなければならないかを決定します。

親クラスのメソッドが例外をスローしない場合、子クラスのメソッドはチェック済みの例外をスローできませんが、チェックされていない場合はスローできます。

これを示すためのコード例を次に示します。

class Parent {
    void doSomething() {
       //...
    }
}

class Child extends Parent {
    void doSomething() throws IllegalArgumentException {
       //...
    }
}

次の例では、オーバーライドするメソッドがオーバーライドされたメソッドで宣言されていないチェック済みの例外をスローするため、コンパイルに失敗します。

class Parent {
    void doSomething() {
       //...
    }
}

class Child extends Parent {
    void doSomething() throws IOException {
       //Compilation error
    }
}

親クラスのメソッドが1つ以上のチェック済み例外をスローすると、子クラスのメソッドは未チェックの例外をスローできます。宣言されたチェック済み例外のすべて、すべて、またはそのサブセット、さらにそれらが同じスコープまたはより狭いものである限り、さらに多くの例外があります。

これは、前の規則にうまく従うコードの例です。

class Parent {
    void doSomething() throws IOException, ParseException {
       //...
    }

    void doSomethingElse() throws IOException {
       //...
    }
}

class Child extends Parent {
    void doSomething() throws IOException {
       //...
    }

    void doSomethingElse() throws FileNotFoundException, EOFException {
       //...
    }
}

どちらの方法もルールを尊重することに注意してください。最初のメソッドは、オーバーライドされたメソッドよりも少ない例外をスローし、2つ目は、それがもっとスローしたとしてもです。それらは範囲が狭いです。

ただし、親クラスのメソッドで宣言されていない、またはより広いスコープで例外をスローするような、チェック済みの例外をスローしようとした場合。コンパイルエラーが発生します。

class Parent {
    void doSomething() throws FileNotFoundException {
       //...
    }
}

class Child extends Parent {
    void doSomething() throws IOException {
       //Compilation error
    }
}

親クラスのメソッドに未チェックの例外が含まれるthrows句がある場合、子クラスのメソッドは、関連していなくても、まったく、または任意の数の未チェックの例外をスローできます。

これがルールを尊重する例です。

class Parent {
    void doSomething() throws IllegalArgumentException {
       //...
    }
}

class Child extends Parent {
    void doSomething()
      throws ArithmeticException, BufferOverflowException {
       //...
    }
}

==== * Q14。次のコードはコンパイルされますか?**

void doSomething() {
   //...
    throw new RuntimeException(new Exception("Chained Exception"));
}

はい。例外をチェーニングするとき、コンパイラはチェインの最初のものだけを気にします、そしてそれは未チェックの例外を検出するので、throws節を追加する必要はありません。


Q15.

throws

句がないメソッドからチェック済み例外をスローする方法はありますか?

はい。コンパイラによって実行された型の消去を利用して、未チェックの例外をスローしていると判断させることができます。チェック例外を投げています:

public <T extends Throwable> T sneakyThrow(Throwable ex) throws T {
    throw (T) ex;
}

public void methodWithoutThrows() {
    this.<RuntimeException>sneakyThrow(new Exception("Checked Exception"));
}


3結論

この記事では、例外について、Java開発者向けの技術面接で見られる可能性があるいくつかの質問について説明しました。これは網羅的なリストではありません、そしてそれはそれ以上の研究の開始としてだけ扱われるべきです。

Baeldungでは、今後のインタビューであなたが成功することを願っています。




  • «** 前へ