Java 例外処理など

今回は、例外処理を習いました。

例外処理(れいがいしょり)とは、プログラムの上位の処理から呼び出されている下位の処理で継続不能、または継続すれば支障をきたす異常事態に陥ったとき、制御を呼び出し元の上位の処理に返し安全な状態になるよう回復処理をすること。その際に発生した異常のことを例外と呼ぶ。

例外処理 - Wikipedia

予期せぬエラーが起きたときにする処理ということらしいっす。 

Javaにおけるエラー

Javaでのエラーは大まかに、

  1. 文法エラー(syntax error)
  2. 実行時エラー(runtime error)
  3. 論理エラー(logic error)

の3つに分類できるようです。そのうち、例外処理は『2. 実行時エラー(runtime error)』に効果的のようです、というか『2. 実行時エラー(runtime error)』だけに注力する感じですかね?

『1. 文法エラー(syntax error)』に関しては、コンパイル時にエラーを出してくれるので、コンパイラーに丸投げしておいても大丈夫?かと。エディターのソースコード上でエラーが出るので気づきやすいエラーです。

package exceptionSample;

public class SyntaxErrorSample {

  public static void main(String[] args) {
    // 『;』忘れでコンパイルエラーの例
    System.out.println("『;』が記述されてない~!")

  }

}

『3. 論理エラー(logic error)』に関しては、コンパイルエラー、実行時エラー、ともに起きないので、自力で不具合を起こしている個所を見つけねばなりません(地獄)。

package exceptionSample;

public class LogicErrorSample {

  public static void main(String[] args) {
    int leftNumber  = 3;
      int rightNumber = 5;
      
      // 本当は8と出力して欲しいが、空の『""』が邪魔してる
      System.out.println("合計" + leftNumber + "" + rightNumber);

  }

}

『2. 実行時エラー(runtime error)』に関しては、コンパイルエラーは起こらないものの、実行時エラーが発生します。

package exceptionSample;

public class RuntimeErrorSample {

  public static void main(String[] args) {
    String[] animals = {"孫悟空", "猪八戒", "沙悟浄", "牛魔王", "鉄扇公主", "紅孩児", "金角大王", "銀角大王"}; 
    // コンパイルエラーは起きないけど、実行時エラーになる
    // 配列animalsは、0~7までの要素しかないのに、8番目にアクセスしようとしてエラー
    System.out.println(animals[8]);
  }

}

 

例外処理の出番です

Javaで例外処理を実装する場合、 

  • try-catch文
  • try-with-resources文

の2つが有名みたいです。 

まずは、try-catch文

package exceptionSample;

public class TryCatchSample {

  public static void main(String[] args) {
    // try-catch文
    try {
      
      String str = null;
      System.out.println(str.length());
      
    // ↓ エラーが起きたら処理
    } catch (Exception e) {
      // エラー内容を表示
      e.printStackTrace();
      // ↑ エラーが起きた場合はここまでしか処理されない
    }
    // ↓ エラーが起きた場合は、表示されない
    System.out.println("END");

  }

}

実行すると、

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 8
	at exceptionSample.RuntimeErrorSample.main(RuntimeErrorSample.java:9)
    

というエラーが表示されますが、try句の中でエラーが起きた場合、catch句に処理が移るためです。e.printStackTrace()が実行されると処理は終了します。

もう一つ、try-catch文。Eclipseで「Javaプロジェクト」>「src」の上で右クリックし、「新規」>「フォルダ」で『file』というフォルダを作って、

f:id:ts0818:20170711225450j:plain

その中に『data.txt』ファイルを作成しておきます。

f:id:ts0818:20170711225707j:plain

「パッケージ・エクスプローラー」の構成が下記のようになります。 

f:id:ts0818:20170711224933p:plain

『data.txt』の上で右クリックし、「プロパティ」を選択します。

f:id:ts0818:20170711230145j:plain

「ロケーション(L):」のほうのパスを使用します。

f:id:ts0818:20170711230311j:plain

 

package exceptionSample;

import java.io.FileWriter;
import java.io.IOException;

public class TryCatchSample {

	public static void main(String[] args) {
		//
		FileWriter fw = null;
		try {
			fw = new FileWriter("C:\\workspace\\ExceptionSample\\src\\file\\data.txt");
			fw.write("abcabc");

		} catch(IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fw.close();
			} catch (IOException e) {
				// 
				e.printStackTrace();
			}
		}
		System.out.println("書き込みました。");

	}

}

続いて、try-withs-resources文。

package exceptionSample;

import java.io.FileWriter;
import java.io.IOException;

public class TryWithResourcesSample {

	public static void main(String[] args) {
		//
		try(FileWriter fw = new FileWriter("C:\\workspace\\ExceptionSample\\src\\file\\data.txt");) {
			fw.write("efgefg");
		} catch(IOException e) {
			e.printStackTrace();
		}
		System.out.println("書き込みました。");

	}

}

try-with-resources文を使うと、FileWriterクラスのインスタンスをclose()しなくても、自動でclose()してくれるみたいです。finally句が省略できます。

⇩  下記サイトが詳しいです

【Java】try-catch文でfinallyを省略する【try−with−resource構文】 - 8t's BBR

 

例外処理を先送りにすることもできます。

package exceptionSample;

public class ExceptionSendSample {

  public static void main(String[] args) {
    // 
        try {
      sub();
    } catch (Exception e) {
      // 
      e.printStackTrace();
    }
  }
  
  public static void sub() throws Exception  {
    subsub();
  }
  
  public static void subsub() throws Exception  {
    String s = null;
    System.out.println(s.length());
  }

}

本当は、subsub()メソッド内でtry-catchすべきですが、メソッドにthrows Exceptionをつけることで、呼び出し元のsub()に任せた、となり、sub()にもthrows Exceptionをつけると、main()メソッドに任せたとなるようです。

最後まで、throws Exceptionをつけると、Exceptionクラスにすべて任せるということになります。

 

自分で独自に例外クラスを作成して利用することもできます。

public class MyExceptionSample extends Exception {
  public MyExceptionSample(String msg) {
    super(msg);
  }
}
public class Main {
  public static void main(String[] args) {
    try{
      //
      throw new MyExceptionSample("自分で作った例外クラス");
    
    } catch(Exception e) {
      System.out.println(e);
    }
  }
}

例外処理もどれを使っていくべきか判断が難しいですね。