
103. 継承時の例外チェックにはどのようなルールが適用されますか?
私の質問が正しく理解できれば、継承時に例外を処理するためのルールについて尋ねていることになります。関連するルールは次のとおりです。- 子孫/実装でオーバーライドまたは実装されたメソッドは、スーパークラス/インターフェイス メソッドの例外よりも上位の階層にあるチェック例外をスローできません。
public interface Animal {
void speak() throws IOException;
}
このインターフェイスを実装する場合、より一般的なスロー可能な例外 (例: Exception、Throwable ) を公開することはできませんが、既存の例外をFileNotFoundExceptionなどのサブクラスに置き換えることはできます。
public class Cat implements Animal {
@Override
public void speak() throws FileNotFoundException {
// Some implementation
}
}
- サブクラス コンストラクターのthrows句には、オブジェクトを作成するために呼び出されたスーパークラス コンストラクターによってスローされるすべての例外クラスを含める必要があります。
public class Animal {
public Animal() throws ArithmeticException, NullPointerException, IOException {
}
次に、サブクラスのコンストラクターもそれらをスローする必要があります。
public class Cat extends Animal {
public Cat() throws ArithmeticException, NullPointerException, IOException {
super();
}
または、メソッドと同様に、より一般的な別の例外を指定できます。この場合、Exceptionを示すことができます。これは、これがより一般的であり、スーパークラスで示される 3 つの例外すべての共通の祖先であるためです。
public class Cat extends Animal {
public Cat() throws Exception {
super();
}
104.finally ブロックが実行されないコードを作成できますか?
まず、 finallyとは何かを思い出しましょう。前に、例外キャッチのメカニズムを調べました。tryブロックは例外がキャッチされる場所を指定し、catchブロックは対応する例外がキャッチされたときに呼び出されるコードです。finallyキーワードでマークされたコードの 3 番目のブロックは、catch ブロックを置き換えたり、catch ブロックの後に置くことができます。このブロックの背後にある考え方は、tryブロックまたはcatchブロックで何が起こったかに関係なく (例外があるかどうかに関係なく)、そのコードは常に実行されるということです。このブロックが実行されないインスタンスはまれであり、異常です。最も単純な例は、finally ブロックの前に System.exit(0)が呼び出され、プログラムが終了する場合です。
try {
throw new IOException();
} catch (IOException e) {
System.exit(0);
} finally {
System.out.println("This message will not be printed on the console");
}
他にも、 finallyブロックが実行されない 状況がいくつかあります。
-
たとえば、重大なシステム エラーや、アプリケーションのクラッシュを引き起こす何らかのエラー (たとえば、アプリケーション スタックがオーバーフローしたときに発生するStackOverflowError ) によって引き起こされるプログラムの異常終了です。
-
もう 1 つの状況は、デーモンスレッドがtry-finallyブロックに入った後、プログラムのメイン スレッドが終了する場合です。結局のところ、デーモン スレッドは優先度も必須でもないバックグラウンド作業用であるため、アプリケーションはデーモン スレッドが終了するのを待ちません。
-
最も無知な例は、tryまたはcatchブロック内の無限ループです。一度ブロックに入ると、スレッドはそこで永久にスタックします。
try { while (true) { } } finally { System.out.println("This message will not be printed on the console"); }

105. 単一の catch ブロックで複数の例外を処理する例を作成します。
1) この質問が正しく行われたかどうかわかりません。 私が理解している限り、この質問は複数のcatchブロックと 1 つのtryを指しています。
try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
System.out.print("Oops! There was an exception: " + e);
} catch (IOException e) {
System.out.print("Oops! There was an exception: " + e);
} catch (Exception e) {
System.out.print("Oops! There was an exception: " + e);
}
tryブロック で例外がスローされた場合、関連するcatchブロックは上から下に順番に例外をキャッチしようとします。例外がcatchブロックの 1 つに一致すると、残りのブロックはその例外をキャッチして処理できなくなります。これはすべて、 catchブロックのセット内で、より狭い例外がより一般的な例外の上に配置されることを意味します。たとえば、最初のcatchブロックがExceptionクラスをキャッチした場合、後続のブロックはチェックされた例外をキャッチしません (つまり、Exceptionのサブクラスを持つ残りのブロックはまったく役に立ちません)。 2) あるいは、質問が正しく行われた可能性があります。 その場合、次のように例外を処理できます。
try {
throw new NullPointerException();
} catch (Exception e) {
if (e instanceof FileNotFoundException) {
// Some handling that involves a narrowing type conversion: (FileNotFoundException)e
} else if (e instanceof ArithmeticException) {
// Some handling that involves a narrowing type conversion: (ArithmeticException)e
} else if(e instanceof NullPointerException) {
// Some handling that involves a narrowing type conversion: (NullPointerException)e
}
catch を使用して例外をキャッチした後、オブジェクトが特定の型に属しているかどうかをチェックする、instanceof演算子を使用してその特定の型を検出しようとします。これにより、悪影響を恐れることなく、自信を持って縮小型変換を実行できるようになります。同じ状況ではどちらのアプローチも適用できます。私がこの質問について疑問を表明したのは、2 番目の選択肢が良いアプローチとは言えないからです。私の経験では、これに遭遇したことはなく、複数の catch ブロックを含む最初のアプローチが広く普及しています。
106. 例外を強制的にスローできる演算子はどれですか? 例を書いてください
上記の例ではすでに何度か使用していますが、もう一度繰り返します: throwキーワード。手動で例外をスローする例:
throw new NullPointerException();
107. main メソッドは例外をスローできますか? もしそうなら、それはどこへ行くのでしょうか?
まず最初に注意しておきたいのは、mainメソッドは単なる通常のメソッドにすぎないということです。はい、プログラムの実行を開始するために仮想マシンによって呼び出されますが、それを超えて、他のコードから呼び出すこともできます。つまり、throwsキーワードの後にチェック例外を示すことに関する通常の規則も適用されます。
public static void main(String[] args) throws IOException {
したがって、例外がスローされる可能性があります。main が(他のメソッドではなく) プログラムの開始点として呼び出される場合、スローされる例外はすべてUncaughtExceptionHandler
によって処理されます。各スレッドにはそのようなハンドラーが 1 つあります (つまり、各スレッドにそのようなハンドラーが 1 つあります)。必要に応じて、独自のハンドラーを作成し、 public static void main(String[] args) throws IOException {setDefaultUncaughtExceptionHandler メソッドを public static void main(String[] args) throws IOException {Thread オブジェクトで呼び出して設定できます。
マルチスレッド化

108. マルチスレッド環境で動作するためのどのようなメカニズムを知っていますか?
Java におけるマルチスレッドの基本メカニズムは次のとおりです。-
synchronizedキーワード。スレッドがメソッド/ブロックに入るときにロックし、他のスレッドが入るのを防ぐ方法です。
-
volatileキーワードを使用すると、さまざまなスレッドによってアクセスされる変数への一貫したアクセスが保証されます。つまり、この修飾子が変数に適用されると、その変数の割り当てと読み取りを行うすべての操作がアトミックになります。つまり、スレッドは変数をローカル メモリにコピーして変更することはありません。元の値が変更されます。
-
Runnable — このインターフェース (単一のrun()メソッドで構成されます) をクラスに実装できます。
public class CustomRunnable implements Runnable { @Override public void run() { // Some logic } }
そのクラスのオブジェクトを作成したら、そのオブジェクトをThreadコンストラクターに渡してstart()メソッドを呼び出すことで、新しいスレッドを開始できます。
Runnable runnable = new CustomRunnable(); new Thread(runnable).start();
startメソッドは、実装されたrun()メソッドを別のスレッドで実行します。
-
Thread — このクラスを継承し、そのrunメソッドをオーバーライドできます。
public class CustomThread extends Thread { @Override public void run() { // Some logic } }
このクラスのオブジェクトを作成してstart()メソッドを呼び出すことで、新しいスレッドを開始できます。
new CustomThread().start();
- 同時実行— これは、マルチスレッド環境で作業するためのツールのパッケージです。
内容は次のとおりです。
-
同時コレクション— これは、マルチスレッド環境で動作するために明示的に作成されたコレクションのコレクションです。
-
キュー— マルチスレッド環境用の特殊なキュー (ブロッキングおよびノンブロッキング)。
-
シンクロナイザー- これらは、マルチスレッド環境で作業するための特殊なユーティリティです。
-
エグゼキュータ— スレッド プールを作成するメカニズム。
-
ロック— 標準のものより柔軟なスレッド同期メカニズム (synchronized、wait、notify、notifyAll)。
- Atomics — マルチスレッド用に最適化されたクラス。それぞれの操作はアトミックです。
-
109. スレッド間の同期について教えてください。wait()、notify()、notifyAll()、join() メソッドは何のためにありますか?
スレッド間の同期は、 synchronizedキーワードに関するものです。このモディファイアはブロックに直接配置できます。
synchronized (Main.class) {
// Some logic
}
または、メソッド シグネチャ内で直接次のように指定します。
public synchronized void move() {
// Some logic }
前に述べたように、同期は、1 つのスレッドが入ったときにブロック/メソッドを他のスレッドにロックするメカニズムです。コードブロック/メソッドを部屋として考えてみましょう。ある糸が部屋に近づき、侵入し、鍵でドアをロックします。他のスレッドが部屋に近づくと、ドアがロックされていることを確認し、部屋が使用可能になるまで近くで待機します。最初のスレッドが部屋内での用事を終えると、ドアのロックを解除し、部屋から出て、キーを放します。私がキーについて何度か言及したのには理由があります。それは、類似したものが実際に存在するからです。これはビジー/フリー状態を持つ特別なオブジェクトです。Java のすべてのオブジェクトにはそのようなオブジェクトがあるため、同期ブロックを使用するときは、かっこを使用してミューテックスがロックされるオブジェクトを示す必要があります。
Cat cat = new Cat();
synchronized (cat) {
// Some logic
}
最初の例 ( Main.class ) で行ったように、クラスに関連付けられたミューテックスを使用することもできます。結局のところ、メソッドでsynchronized を使用するときは、ロックするオブジェクトを指定しませんよね。この場合、非静的メソッドの場合、ロックされるミューテックスは thisオブジェクト、つまりクラスの現在のオブジェクトです。静的メソッドの場合、現在のクラス ( this.getClass(); ) に関連付けられたミューテックスはロックされます。wait()は、現在のモニター (アンカーのようなもの) にアタッチしているかのように、ミューテックスを解放し、現在のスレッドを待機状態にするメソッドです。このため、このメソッドは同期されたブロックまたはメソッドからのみ呼び出すことができます。そうでなければ、何が待っていて、何が解放されるのでしょうか?)。これはObjectクラスのメソッドであることにも注意してください。そうですね、1 つではなく 3 つです。
-
wait()は、別のスレッドがこのオブジェクトのNotice()メソッドまたはNotifyAll()メソッドを呼び出すまで、現在のスレッドを待機状態にします(これらのメソッドについては後で説明します)。
-
wait(long timeout)は、別のスレッドがこのオブジェクトのnotify()メソッドまたはnotifyAll()メソッドを呼び出すか、timeout で指定された時間が経過するまで、現在のスレッドを待機状態にします。
-
wait(long timeout, int nanos) は前のメソッドと似ていますが、ここでnanos を使用するとナノ秒 (より正確なタイムアウト) を指定できます。
-
notify() を使用すると、現在の同期ブロックを待機している 1 つのランダムなスレッドを起動できます。繰り返しますが、このメソッドは同期されたブロックまたはメソッド内でのみ呼び出すことができます(結局のところ、他の場所では起動する人は誰もいないでしょう)。
-
NoticeAll() は、現在のモニターで待機しているすべてのスレッドを起動します (これも同期されたブロックまたはメソッドでのみ使用されます)。
110. スレッドを停止するにはどうすればよいですか?
ここで最初に言っておきたいのは、run() が最後まで実行されると、スレッドは自動的に終了するということです。ただし、メソッドが完了する前に、スケジュールより前にスレッドを強制終了したい場合があります。どうしようか?Threadオブジェクトでstop()メソッドを使用できるでしょうか? いいえ!このメソッドは非推奨であり、システムクラッシュを引き起こす可能性があります。 さて、それではどうでしょうか?これを行うには 2 つの方法があります。 1 つ目は、内部のブール フラグを使用することです。例を見てみましょう。スレッドが完全に停止するまで画面上に特定の語句を表示するスレッドの実装があります。
public class CustomThread extends Thread {
private boolean isActive;
public CustomThread() {
this.isActive = true;
}
@Override
public void run() {
{
while (isActive) {
System.out.println("The thread is executing some logic...");
}
System.out.println("The thread stopped!");
}
}
public void stopRunningThread() {
isActive = false;
}
}
stopRunningThread()メソッド を呼び出すと、内部フラグが false に設定され、run()メソッドが終了します。mainで呼び出してみましょう:
System.out.println("Program starting...");
CustomThread thread = new CustomThread();
thread.start();
Thread.sleep(3);
// As long as our main thread is asleep, our CustomThread runs and prints its message on the console
thread.stopRunningThread();
System.out.println("Program stopping...");
その結果、コンソールに次のような内容が表示されます。
public class CustomThread extends Thread {
@Override
public void run() {
{
while (!Thread.interrupted()) {
System.out.println("The thread is executing some logic...");
}
System.out.println("The thread stopped!");
}
}
}
メイン で実行中:
System.out.println("Program starting...");
Thread thread = new CustomThread();
thread.start();
Thread.sleep(3);
thread.interrupt();
System.out.println("Program stopping...");
これを実行した結果は最初のケースと同じですが、私はこのアプローチのほうが気に入っています。記述するコードが減り、既成の標準機能をより多く使用できるようになりました。それでは、今日はここまでです!
GO TO FULL VERSION