1. ホーム
  2. java

Java面接のポイント3--例外処理(Exception Handling)

2022-02-19 03:35:39
<パス

javaの例外処理 (Exception)

例外とは、プログラム実行中に起こる好ましくない事態のことで、適切に処理されないと、おかしな結果になったり、プログラムが終了したりします。例外ハンドラは、これらの例外が発生したときに処理するコードです。そこで、ここでは3つだけ紹介します。

1. 例外(エクセプション)とは

例外とは、プログラム実行中に起こる好ましくないことで、適切に処理されないと、おかしな結果になったり、プログラムが終了したりします。例外処理とは、これらの例外が発生したときに処理するコードです。javaもjavascriptも例外処理にtry/catchを使用しています。

1.1 javaにおける例外

javaでは例外はオブジェクトでもあります。
まずは図解から


画像クレジットを表示します。 http://voyager.deanza.edu/~hso/cis35a/lecture/java13/intro/hier.html
そのお父さんは Throwable (インタビューはテストします、ノックオンウッド)。という兄弟もいます。 Error .

エラーと例外の違い

<ブロッククオート

ErrorはThrowableのサブクラスで、合理的なアプリケーションがキャッチしようとすべきではない深刻な問題を示しています。

<ブロッククオート

Exceptionクラスとそのサブクラスは、合理的なアプリケーションがキャッチしたいと思うような条件を示すThrowableの一種です。

1.2 チェックされる例外とチェックされない例外

  • チェックされた例外 チェックされた例外は、コンパイル時に処理されることが要求されます。チェックされた例外は、コンパイル時に (ハンドラの有無に関わらず) 処理されたかどうかが確認されるので コンパイル時例外 . Exceptionの子クラスであってもRuntimeExceptionでない場合はチェックされるため、コードを書く際にハンドラを追加する必要があります。IDEを使用する場合は、コードを書くときにこのような例外を処理するように要求されます。
    • 例えば CloneNotSupportedException、IOException、SQLException。
      InterruptedException、FileNotFoundException
  • チェックされていない例外 は、次のようにも呼ばれます。 実行時例外 プログラムの実行中に発生するためです。このような例外は、ハンドラを追加して処理することもできますし、処理しないままにしておくこともできます。RuntimeExceptionの子孫であるクラスがあれば、それは未処理の例外である。
    • 例えば IllegalMonitorStateExceptionです。
      ConcurrentModificationException、NullPointerException。
      IndexOutOfBoundException、NumberFormatException

1.3 エラーと未チェックの例外の違い

どちらも実行時に発生しますが、errorは処理することをお勧めしません。catchを付けても直らないことがほとんどです。一方、RuntimeExceptionは、処理することができます。

2. 例外を処理する方法

宣言時に例外を投げることを宣言するメソッドがあります。 チェックされた例外である場合、そのメソッドはハンドルを付けて呼び出す必要があります。
チェックされた例外は、爆弾のようなものです。例えばメソッドAのどこかで爆弾が投げられた場合、あるいはどこかから爆弾を受け取った場合(例外を投げた別のメソッドの呼び出し)、2つの解決策があります。

  • <強い 自分で取り壊す(try-catch-finally)。 そうすれば、メソッドAを呼び出すメソッドは、この爆弾(例外)を気にする必要はありません。
  • 投げ続けて、メソッドAを呼び出した人がそれを処理する(Aのメソッド宣言に追加する throws .)

最初のオプションを使用する場合、メソッドBがメソッドAを呼び出すとき、メソッドAはすでに爆弾を解除しており、メソッドBは何も心配する必要がありません。 .
2つ目のアプローチを採用した場合、メソッドBは同時に爆弾を受けることを知りながらメソッドAを呼び出すので、解決策は2つ、取り壊すか、投げ続けるかです。

2.1 方法 爆弾の信管を外す try-catch-finallyの使用

try-catchを使用します。

一般的な配列の境界外例外です。 はコンパイル時にハンドルが必要ないため、チェックされていない例外で、一般的な 初心者 実行時例外です。(処理する必要はありませんが、処理しようと思えば可能です)。

import java.io.*;
public class ExceptionTest1 {
   public static void main(String args[]) {
      try {
         int a[] = new int[2];
         System.out.println(a[3]); //array out-of-bounds access
      } catch (ArrayIndexOutOfBoundsException e) {
         System.out.println(e);//doesn't do anything meaningful, but stops the program from dying halfway through.
      }
      System.out.println("run successfully");
   }
}


tryの後には、異なるエラーを分離するために、いくつかのcatchを続けることができます。

try {
   //doing something
} catch (Exception1 e) {
	// handle the first type exception
    System.out.println("Exception1 happened")
} catch (Exception2 f){
	// handle the first type exception
    System.out.println("Exception2 happened")
}


例外が発生した後、それがException1型であれば最初のハンドルで処理され、Exception1型でなければ次のキャッチに移り、Exception2型であれば2番目のキャッチブロックが処理します。
Exception1とException2が父と息子の場合、息子が先に検出されることになります。なぜなら、父が先に検出されると、息子のキャッチブロックまでたどり着けないからです。

finally ブロックです。

finallyブロックは、とにかく起きるブロックです。catchの中のコードは例外が発生しなければ実行されませんが、finallyの中のコードはいずれにせよ実行されます。(ただし、tryやcatchの中のコードが System.exit(1) ) これは通常、ファイルをクローズするときに使われます。

      try {
         //doing something
      } catch (Exception e) {
      	//handle the exception
      }finally {
         //the code that will definitely be executed.
      }
   }
}


また try-finally も合法です。

2.2 継続の仕方 ダンピング 例外をスローする

使用方法 throws キーワード

//m1 throws an exception
void m1 throws FileNotFoundException(){
	//Probably wants to read some files and doesn't want to think about what to do if the files can't be found. (dump)
}
//m2 calls m1, which is equivalent to receiving this exception from m1, not handling it itself, and continuing to dump it out.
void m2 throws FileNotFoundException(){
	m1();//want to use m1 method, m1 declare if you want to use I have to consider the file can not be found.
	// But m2 still don't want to consider what to do if the file can't be found.
}


合成例を見るには

次のコードは、例外を受け取り、それを正しく処理しなかったため、コンパイルエラーを発生させます。

import java.io.File;
import java.io.FileReader;
// will have compile errors
public class ReadFileTest {
   public static void main(String args[]) {
      getFile();
   }
   public static void getFile(){
   	   File file = new File("file.txt");
       FileReader fr = new FileReader(file);//error: unreported exception FileNotFoundException; must be caught or declared to be thrown
   }
}


FileReader のコンストラクタが例外を投げるためです。

public FileReader(String fileName) throws FileNotFoundException


そのため、getFileメソッドがFileReaderを呼び出す際に、この例外を処理する必要があります。

上記2つのメソッドを使って例外を処理する例を示します。

import java.io.File;
import java.io.FileReader;
import java.io.FileNotFoundException;
public class ReadFileTest {
   public static void main(String args[]) {
   		getFile1();
   		System.out.println("=============");
        try{
           // Since getFile2 throws out the exception again, the main method has to handle it.
           getFile2();
        }catch(FileNotFoundException e){
           System.out.println("Exception handled in main");
        }
      
   }
   //getFile1 has chosen to handle itself, do not bother to call its method
   public static void getFile1() {
		try{
   	   		File file = new File("file.txt");
       		FileReader fr = new FileReader(file);
       	}catch(FileNotFoundException e){
       		System.out.println("Exception handled in getfile1");
       }
   }
   //getFile2 has chosen not to handle, continue throws
   public static void getFile2() throws FileNotFoundException{
   	   File file = new File("file.txt");
       FileReader fr = new FileReader(file);
   }
}


実行結果。

Exception handled in getfile1
=============
Exception handled in main


一般的に言って、すべての例外はmainメソッドによって解決されているはずです。もし main メソッドも無責任に放り出されます。

import java.io.File;
import java.io.FileReader;
import java.io.FileNotFoundException;
public class ReadFileTest {
   public static void main(String args[]) throws FileNotFoundException{
   		getFile1();
   		System.out.println("=============");
        getFile2();
      
   }
   public static void getFile1() {
		try{
   	   		File file = new File("file.txt");
       		FileReader fr = new FileReader(file);
       	}catch(FileNotFoundException e){
       		System.out.println("Exception handled in getfile1");
       }
   }
   public static void getFile2() throws FileNotFoundException{
   	   File file = new File("file.txt");
       FileReader fr = new FileReader(file);
   }
}


これはうまくいく。ドキュメントなしで実行すると(例外が発生する)、次のような結果になります。

Exception handled in getfile1
=============
Exception in thread "main" java.io.FileNotFoundException: file.txt (No such file or directory)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.<init>(FileInputStream.java:138)
	at java.io.FileReader.<init>(FileReader.java:72)
	at ReadFileTest.getFile2(ReadFileTest.java:21)
	at ReadFileTest.main(ReadFileTest.java:8)


3. カスタム例外を適用する方法

3.1 カスタム例外クラスを作成する方法

は例外とその子を拡張する

1. class New1Exception extends Exception { } // Create a checked exception
2. class NewException extends IOExcpetion { } // Create an IO-related exception
3. class NewException extends RuntimeException { } // Create an Unchecked exception



例として(こんなに簡単なんです)。

import java.io.*;
class MyException extends Exception 
{ 
    public MyException(String s) 
    { 
        super("a MyException happens: " + s); 
        // there are a few other things that can be done
    } 
} 


3.2 カスタム例外をダンプ(スロー)する方法

throw と throws

throw は、メソッドまたはコードブロックの内部で、次のように使用します。 を投げる 例外を投げる。
throwsはメソッド宣言時に、そのメソッドが例外をスローすることを記述します。

先ほどのMyExceptionを使った例を書いてみてください。

import java.io.*;
public class Main 
{ 
    public static void main(String args[]) 
    { 
        try { 
            throwTest();
        } catch (MyException e) { 
            System.out.println("Caught something"); 
            System.out.println(e.getMessage()); 
        } 
        //throwTest2 is a normal method, the thrown exception is handled by itself.
        throwTest2();
        // another block is used to test test3.
        //If written in the same block, throwTest() will not be executed after throwTest() throws an exception
        try { 
            throwTest3();
        } catch (MyException e) { 
            System.out.println("Caught something"); 
            System.out.println(e.getMessage()); 
        } 
    } 
    // do not handle themselves, throw out after continuing to tell the call in the method declaration their own methods need to handle
    public static void throwTest() throws MyException {
        throw new MyException("something"); 
    }
    //handle yourself, into a normal method
    public static void throwTest2() {
        try {
            throw new MyException("somethingElse"); 
        } catch (MyException e) {
            System.out.println("Caught somethingElse"); 
            System.out.println(e.getMessage()); 
        } 
    }
    //handle it yourself, and keep throwing it out in catch.
    public static void throwTest3() throws MyException{
        try {
            throw new MyException("somethingElse2"); 
        } catch (MyException e) {
           // A very irresponsible catch, but legal.
           throw e;
        }
    }
}  


出力します。

Caught something
a MyException happens: something
Caught somethingElse
a MyException happens: somethingElse
Caught something
a MyException happens: somethingElse2