目次

例外処理

実行中の例外

CatText2.java で,TextFieldに数字以外の文字を入力したり、小数点を2つ使ったりすると、エラーが起きてDOSプロンプトにメッセージが出ます。(スクロールしてしまって上部が見えないかもしれませんので全文を載せておきます)

$ java CatText2
Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: "2a"
        at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224)
        at java.lang.Double.parseDouble(Double.java:482)
        at CatText2.actionPerformed(cattext2.java:39)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1849)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2169)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:234)
        at java.awt.Component.processMouseEvent(Component.java:5488)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3126)
        at java.awt.Component.processEvent(Component.java:5253)
        at java.awt.Container.processEvent(Container.java:1966)
        at java.awt.Component.dispatchEventImpl(Component.java:3955)
        at java.awt.Container.dispatchEventImpl(Container.java:2024)
        at java.awt.Component.dispatchEvent(Component.java:3803)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4212)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3892)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3822)
        at java.awt.Container.dispatchEventImpl(Container.java:2010)
        at java.awt.Window.dispatchEventImpl(Window.java:1774)
        at java.awt.Component.dispatchEvent(Component.java:3803)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)

最初の赤いところに注目。NumberFormatException「数の形式の例外」とでも訳しましょうか

javacでコンパイルする時にもエラーが起きますが、これがうまくいっても実行時にこのように状況によってはエラーが起きます。javaではこれを例外 (Exception)と呼んでいます。

この例は、作成時には数値の入力だけしか考えていなかったのに文字列を入力したことで起こった例外です。計算の結果は前の計算の値がそのまま残ります。自分で使うだけならこれでもいいのですが、他人に使ってもらうプログラムだとどこが違うかを知らせたり、とりあえず計算結果が出せないことを伝えなければなりません。

対策

いろいろな方法があります。

1.文字列から数値にする前に全部が数字であることを確認する。
2.そもそも数字しか入力できなくする。
3.エラーが起きたときに実行する処理を作って登録しておく

1,2は細かな処理が可能ですが、完全を期するのは難しいです。マイナス記号も入れることがありますが、文字列の途中にあるとエラーになります。小数点が1つ以上ないことも確認しなければなりません。

一般にエラー処理や操作の説明をていねいに入れるとプログラムの量は3倍ぐらいになります。これはごく普通のことです。

もちろんあらゆる入力を想定して手を打ってもいいのですが、それにもれた状況に対しても対応できる方法があります。その一つが例外処理です。マニュアルには例外処理とありますが、厳密な言葉遣いをせずエラー処理ということもあります。

try-catch

例外が発生しそうな処理をtryのブロックで囲みます。例外が起こると処理を中断して、次のcatchのブロック内を実行します。例外が起こらないときはcatch部分は実行されません。

try {
	例外が発生しそうな処理
} catch (例外クラス 変数) {
	例外処理
}

エラーの起こり方と、どう処理したいかによっていろいろな書き方があります。最も簡単な例で動作を確認します。

例外処理例1

if (e.getSource() == button) {
	double x = 0 ;
	double y = 0 ;
	try {
		x = Double.parseDouble(text1.getText());
		y = Double.parseDouble(text2.getText());
	} catch (Exception ex) { 
		// とくに何もしない
	}
	label.setText( Double.toString( x + y ) );
}

最初に x y に 0 を入れています。これは値が代入できないときに未定義の変数を使うことにならないようにしています。

上の欄に数字以外のものが書かれているとtryの中の x = の部分で例外が起こり、すぐに catch ブロックに進みます。そこでは何もしないので x にも y にも入力した値が代入されず、0 のままになります。従って答えも0になります。

下の欄だけに数字以外のものが書かれているとtryの中の x = の作業は正常に終わり、下の欄の作業である y = で例外になって catch ブロックに進みます。その結果 x には入力した値が代入され y には値が代入さないので 0 のままになります。従って答えは x の値になります。。

処理の仕方は上と下で異なり不自然ですが、エラーは出力されなくなりますし、前の計算の答が残っているということはなくなります。

エラーの種類に対処

Exception ex はエラーの状態を表すクラス名とオブジェクト名(変数名)です。ActionEvent e と事情がよく似ています。本来ならexでエラーの状態を調べるのですが、実際にはクラス名の方でエラーの種類を識別します。

起こる可能性のある例外にいくつか種類があるときは次のようにします。

if (e.getSource() == button) {
	double x = 0 ;
	double y = 0 ;
	try {
		x = Double.parseDouble(text1.getText());
		y = Double.parseDouble(text2.getText());
	} catch (NumberFormatException ex) {
		// 処理1
	} catch (Exception ex) { 
		// 処理2
		// 全ての例外がここでつかまる
	}
	label.setText( Double.toString( x + y ) );
}

この例では NumberFormatException「数の形式の例外」の時には処理1を、それ以外は処理2をします。NumberFormatException と書くとその例外処理だけを捕まえる(catch)すると考えてください。Exception は例外全部を指しますのでここでは「その他」の例外全部を捕まえます。

たとえば次のような例が考えられます。

例外処理例2

if (e.getSource() == button) {
	double x = 0 ;
	double y = 0 ;
	String kekka = "" ;
	try {
		x = Double.parseDouble(text1.getText());
		y = Double.parseDouble(text2.getText());
		kekka = Double.toString( x + y ) ;
	} catch (NumberFormatException ex) {
		kekka = "数値の形式が違います "; 
	} catch (Exception ex) { 
		kekka = "何か変です" ;
	}
	label.setText( kekka );
}

例外処理にも考え方があります

上記の例では、どちらの入力に間違いがあるかは示していません。どちらが間違っているかあるいは両方間違っているかを示したいときにはどうすればよいでしょうか。

たとえば次のような例が考えられます。

例外処理例3

if (e.getSource() == button) {
	double x = 0 ;
	double y = 0 ;
	String kekka = "" ;
	try {
		x = Double.parseDouble(text1.getText());
	} catch (NumberFormatException ex) {
		kekka = text1.getText() + " ?? ";
	} catch (Exception ex) { 
		kekka = "何か変です" ;
	}
	try {
		y = Double.parseDouble(text2.getText());
	} catch (NumberFormatException ex) {
		if (kekka != "") kekka += "  /  ";
		kekka += text2.getText() + " ?? ";
	} catch (Exception ex) { 
		if (kekka != "") kekka += "  /  ";
		kekka += "何か変です" ;
	}
	if ( kekka == "" ){
		kekka = Double.toString( x + y ) ;
	}
	label.setText( kekka );
}

例外処理のより一番的な形

catch はいろいろな例外の種類ごとにいくつ置いてもかまいません。また、例外が起きなくても、どの例外が起こっても共通でおこなう finally という処理を加えることもできます。

try {
	例外が発生しそうな処理
} catch (例外1クラス 変数) {
	例外処理1
} catch (例外2クラス 変数) {
	例外処理2
} catch (例外3クラス 変数) {
	例外処理3
} finally {
	共通処理
}
もくじ

聖愛高等学校
http://www.seiai.ed.jp/
Last Modified