Back To Main

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┃ ◆Javaで珈琲ブレイク vol.007 後編◆
┃……………………………………………………………………………………………
┃ [不定期] まぐまぐ ID=0000088576 Melma! ID=m00061296
┃……………………………………………………………………………………………
┃ 今回からご覧になる方は、バックナンバーもご活用下さい
┃ http://www.melma.com/mag/96/m00061296/
┃ http://backno.mag2.com/reader/Back?id=0000088576
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

------------------------------------------------------------
◆◇◆◇◆ 在宅パソコンオペレーター大募集!! ◆◇◆◇◆
★時給⇒2,000円 年齢/22歳〜55歳(学生不可)★サイドワーク可
【仕事】自宅のパソコンでオペレーション業務(業務用ソフトのサポート)
【条件】パソコン(Windows限定)メール出来る方。初心者指導いたします。
【問合は】電話03-6221-1465 (株)プログレ採用係 bosyuu@rex-go.com
------------------------------------------------------------

◆目次◆

■BankAccountUserInterface.java
■チェックありExceptionとチェックなしException
■Question 7


前編の引き続きです。

以前vol.005で使用した、ConvertToCelsius1_2.javaを再利用してみましょう。インプットのところは同じです。amountに代入するときはDoubleクラスのparseDoubleを使ってString型からdouble型に変換しています。そして、BufferedReaderのインスタンスをclose()メソッドでストリームを閉じた後、

────────────────────────────────────
BankAccountRuntimeException account;
account = new BankAccountRuntimeException(100000);
// ゼロ以下の場合にのみRuntimeExceptionが発生する
account.withdraw(amount);
System.out.println("残高 : " + account.getBalance());
────────────────────────────────────

とし、try/catch構文もmain()メソッドでもthrowsキーワードも使いません。
もちろん、BankAccountRuntimeExceptionクラスがある同じフォルダに、BankAccountUserInterface.javaをおいて、BankAccountUserInterfaceをコンパイル・実行しください。


■BankAccountUserInterface.java
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━━━━━━━━━ ここから ━━━━━━━━━━━━━━━━━━
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;

/**
* コマンドプロンプト・ユーザーインターフェースを用いてのデモ。
*
* @author Mr.Hack
*/
public class BankAccountUserInterface {

/**
* ユーザーに入力を促し、ゼロ以下が入力されたときは、
* account.withdraw()メソッドがRuntimeExceptionを発生させる。
* 残高は初期化時、100000としてある。
*
* @param args コマンドライン引数
*/
public static void main(String[] args) {

double amount = 0;

System.out.println("===============================================================");
System.out.println(" --- BankAccount RuntimeException テストプログラム --- ");
System.out.println("===============================================================");

System.out.print("引き出し金額を入力せよ : ");

// バッファーとして蓄える
BufferedReader myBufferedReader = new BufferedReader(new InputStreamReader(System.in));
// readLine()メソッドで行単位ごとに読む
try {
amount = Double.parseDouble(myBufferedReader.readLine());
}
catch (IOException e) {
System.out.println("入力ストリームでエラーが発生しました。プログラムを終了します");
return;
}
finally {
try {
//input streamを閉じる
myBufferedReader.close();
}
catch (IOException e) {
System.out.println("入力ストリーム閉鎖中にエラーが発生しました。プログラムを終了します");
}
}

BankAccountRuntimeException account = new BankAccountRuntimeException(100000);
// ゼロ以下の場合にのみRuntimeExceptionが発生する
account.withdraw(amount);
System.out.println("残高 : " + account.getBalance());
}
}
━━━━━━━━━━━━ ここまで ━━━━━━━━━━━━━━━━━━

さて、まずは、ゼロ以下でない数字を入れてみましょう。例えば、1000と入力すると、

────────────────────────────────────
引き出し金額を入力せよ : 1000
残高 : 99000.0
────────────────────────────────────

となり、正常に終了します。-1000と入力するとどうでしょうか?

────────────────────────────────────
Exception in thread "main" java.lang.RuntimeException: 入力した金額は0かマイナスです。amount: -1000.0
at BankAccountRuntimeException.withdraw( BankAccountRuntimeException.java
:41)
at BankAccountUserInterface.main(BankAccountUserInterface.java:53)
────────────────────────────────────

となりますね。不適切な値を入力しなければ、プログラムはちゃんと作動しています。-1000をユーザーが入力したときは、withdraw()メソッドのクライアントであるmain()メソッドはユーザーから受け取った値をdouble型に変換し、そのまま、-1000をwithdraw()メソッドに渡しています。これは、amountはゼロ以下の値ではない、というルールを破ったということを意味します。そのため、RuntimeExceptionが発生してしまったのです。発生したときは、main()メソッド側では、その例外を処理する手段(try/catch構文等)を用意していなかったので、上記の用になってしまったのです。

メソッドを使う側のクライアントがルールを守っていれば、RuntimeExceptionというのはtry/catch構文を書かなくて良かったりと、都合がいいですね。しかし、クライアント側でwitdraw()メソッドのパラメーターとして適切な値を用意しておかないとプログラムは正常に作動しなくなってしまいます。ですから、RuntimeExceptionといえども、メソッドに渡す値がどの値になるか確かではないときは、try/catch構文でスローされたRuntimeExceptionインスタンスをキャッチしてあげないといけないことになりますね。そのために、JavadocでもAPIとしてちゃんとwithdraw()メソッドはRuntimeExceptionをスローしますよということも表記しておいてあげないと、使う側であるクライアントに不慮の事態を招いてしまいますね。

ところで、RuntimeExceptionのサブクラスに、頻出する例外クラスとして、NullPointerException(インスタンス変数がnullを参照している時に、そのインスタンスにメソッドを適用したりする場合に発生)、ArithmeticException(ある数をゼロで割った場合に発生)、IndexOutOfBoundsException(サイズが5である配列にインデックス5としてアクセスした場合に発生(ゼロから始まるため最終のインデックスはこの場合4))というクラスがあります。すべて、ランタイムにスローされます。そのため、コンパイルは出来ますが、実行時に、条件によって例外が発生します。

■チェックありExceptionとチェックなしException
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

さて、RuntimeExceptionを見てきましたが、RuntimeExceptionのように、コンパイル時にチェックされず、条件(状況)によって例外(Exception)を発生する例外をチェックなし(されない)例外(Unchecked Exception)といいます。逆に、IOExceptionのように、コンパイル時にチェックされるExceptionをチェックあり(される)例外(Checked Exception)といいます。Exception以下のサブクラスで、RuntimeException以下のサブクラスだけが、Unchecked Exceptionです。いいかえれば、RuntimeException以下のサブクラス以下以外は、すべて、Checked Exceptionです。また、Error以下のサブクラスは、同じように、コンパイル時にチェックされないので、Unchecked Exceptionに入ります。要約すると


java.lang.Throwable
|
+--java.lang.Exception (Checked)
| |
| +--java.lang.RuntimeException (Unchecked)
|
+--java.lang.Error (Unchecked)

ということになります。Uncheked Exceptionはコンパイル時にはチェックされないので、メソッドで、throwsキーワードを使って宣言する必要はないです。そのため、

────────────────────────────────────
public void withdraw(double amount) throws RuntimeException {
...
}
────────────────────────────────────

の throws RuntimeExceptionを省略して、

────────────────────────────────────
/**
* amount分の金額を引き出す。amountが
* ゼロかマイナスの時、引き落とし金額が残高を上回った時、
* あるいは、一度に引き出せる上限金額を上回った時、例外発生。
*
* @param amount 引き出す金額
* @exception RuntimeException amountがゼロかマイナスの場合、
* 引き出し額が残高を上回った場合、
* 一度に引き出せる金額を上回った場合、
* 例外発生
*/
public void withdraw(double amount) {
if (amount <= 0) {
throw new RuntimeException("入力した金額は0かマイナスです");
}

this.balance -= amount;
}
}
────────────────────────────────────

とすることも可能です。しかしながら、この場合も、このメソッドを使うクライアントのことを考えて、Javadocでは@exceptionをちゃんと付け加えないといけないことに注意してください。

ところで、不適切な値をwithdraw()メソッドにパラメータとして渡されたときにスローするクラスがJavaではちゃんと用意されているのです。 IllegalArgumentExceptionクラスです。このクラスは、RuntimeExceptionを継承しています。Argumentとは実引数を意味します。実引数は、withdraw()メソッドを使う側でwithdrawに渡す値のことを言います。BankAccountUserInterfaceクラスの

withdraw(1000);

の1000が実引数です。逆に、withdraw()の定義側の変数を仮引数(パラメータ)といいます。BankAccountRuntimeExceptionクラスのwithdraw()メソッドの

withdraw(double amount) {
...
}

amountがパラメータです。そのため、アーギュメント(実引数)として不適切な値を渡したときに、スローさせるクラスとしてIllegalArgumentExceptionが用意されています。

ExcpetionのCheckedとUncheckedを理解していることによって、例外処理の理解を助けてくれると思います。どういう時にthrows宣言を省けるのかとか、どういうときにtry/catch構文を使わなくてもいいのか等、Mr.Hackも例外処理にいつも悩まされていました。大切なところなので、しっかりと復習しておいてくださいね。

それでは、今週の宿題にいってみましょう。

■Question 7
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

1.BankAccount.javaを以下のように修正しなさい。

a) スローする例外は全て、IllegalArgumentExceptionに変更しなさい。
b) パラメータ付きのコンストラクタもdeposit()と同じように条件によって、
例外を発生するようにしなさい。

2.BankAccountTest.javaを以下条件を満たすように修正しなさい。

a) main()メソッドでthrowsキーワードは使ってはならない。
b) try/catch構文では、Throwable、Exception、RuntimeExceptionクラスをつ かってはならない。

3.BankAccount.java用以下の条件を満たすようにJavadocを作成しなさい。

a) javadocコマンドを使用するときにauthor名(@author)が
入るようにしなさい。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ヒント

前回は、あなたは、getBlance()メソッドのメソッド名が間違っていることを発見し、BankAccount.javaにgetBalance()メソッドを追加しました。今回は、Exceptionの変更とJavadocの作成を上司に命じられます。Excpetionクラスでは、一般的すぎるというのです。一般的すぎるという意味がいまいち分からず、Java SDK APIで適切な例外クラスをさがしました。すると、メソッドのパラメータ処理には、IllegalArgumentExceptionが当てはまりそうだと早速変更に取りかかります。また、同時に、生まれて初めてのJava Documentationの作成です。上司はやり方を教えてくれません・・。なんか、外資系的だな、とおもいながら、自分で調べると、javadocとコマンドを打てば作成だと言うことがわかりました。

コマンド上でjavadoc BankAccount.java -authorと打ってみると・・・

今回は、あまり、難しくない宿題だと思います。ExceptionクラスをIllegalArgumentExceptionと変えてみてください。それから、java documentationの作成です。この目的は、Javaで珈琲ブレイクの読者の皆さんは、もうおわかりだと思いますが、Readabilityですね。自分が書いたコードを自分以外の人が見たときの中心になる資料が、java documentationです。これが、どうやって作られるのか、実際コードに記述したコメントがどのように現れているのか、確かめてみてください。注意することは@authorはclassに対するコメントにしか入れられません。

今週もいっぱい勉強しましたね。それでは、また来週まで、have a nice day!

Mr.Hack

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
◆Javaで珈琲ブレイク◆
────────────────────────────────────
皆様からの激励・批判のメールをお待ちしております。
【発行者】 Mr.Hack - javacafebreak@hotmail.com
【掲示板】 http://fweb.midi.co.jp/~romanhikou/cafe_entrance.html
※質問は上記の掲示板からどうぞ。
【サイト】 http://mrhack.hoops.ne.jp/
【発行数】 まぐまぐ[853] Melma[130]
【解除】http://mrhack.hoops.ne.jp/
※解除は上記のサイトからいつでもできます。
────────────────────────────────────
(c)2002 MR.HACK ALL RIGHTS RESERVED
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━


© 2002 MR.HACK ALL RIGHTS RESERVED