下準備
テストドライバの導入
第03回目分のテストドライバを導入する。以下の手順で行う。
- ダウンロード のページを開く (ここをクリック)
- プロジェクト「java20XX」にある「test」の左側の「+」をクリック
- ツリーが展開されるので「install-libraries.xml」を右クリック
- 「実行(R)」にマウスカーソルを合わせる
- 「1 Ant ビルド」をクリック
- 「コンソール」タブに"BUILD SUCCESSFUL"と表示されれば成功
- eclipseの画面でプロジェクト「java20XX」を右クリック
- メニューが表示されるので、「更新」あるいは「最新表示」をクリック
- "week03.zip" をデスクトップなどにダウンロード
- eclipseの画面でプロジェクト「java20XX」を右クリック
- メニューから「インポート(I)」を選択
- 「インポート」ウィンドウが表示されるので、「Zip ファイル」あるいは「アーカイブファイル」を選択
- 「次へ(N)」をクリック
- 宛先フォルダー(L): が「java20XX」になっていることを確認
- From archive file: の右側にある 「参照(R)...」あるいは「ブラウズ(R)...」をクリック
- ファイルダイアログが表示されるので、ダイアログ内に表示されたダウンロードしたファイルをダブルクリック
- 前の画面に戻るので、From archive file: のエリアに正しいパスが入力されていることを確認
- フォルダ「/」の左にチェックがついていることを確認 (ついていなければチェックボックスをクリック)
- 「警告を出さずに既存リソースを上書き」にチェックがついていることを確認 (上書きしたくないファイルがある場合はチェックを外す)
- 「終了 (F)」をクリック
第03週目テストドライバの導入に成功すると、java20XX プロジェクトの test フォルダに j1.lesson03.xml というファイルが作成される。
パッケージの作成
前回の演習を参考にして、「j1.lesson03」というパッケージを作成する。
コンソールからの入力を取得するプログラム
コンソールへ2つの整数を入力させ、それらの合計を出力する。
演習
クラスの作成
以下の手順で、パッケージ「j1.lesson03」に「Adder」クラスを作成する。
- 先ほど作成したパッケージ「j1.lesson03」の上で右クリック
- マウスカーソルを「新規」に合わせる
- 「クラス」をクリック
- 新規 Java クラス」というウィンドウが開くので、
- 「パッケージ(K)」が先ほど入力した「j1.lesson03」になっていることを確認すること。間違っていた場合は、ここに「j1.lesson03」と入力する。
- 「名前(M)」に「Adder」と入力する。
- 「どのメソッド・スタブを作成するか?」という項目では、全てのチェックがはずれていることを確認。
- 最後に、全ての項目を確認した後、右下の「終了」ボタンをクリックして確定する。
mainメソッドの作成
クラス「Adder」内にpublic static void main(String[] args) throws IOException から始まるメソッドを作成する。
全体的には次のようになる。
package j1.lesson03; import java.io.*; public class Adder { public static void main(String[] args) throws IOException { } }
骨格テスト
ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。
保存時にエラーが出ていなければ、 以下の手順で骨格テストを実行する。
- testフォルダの中にある03フォルダの中身を表示 (+があればクリックして展開していく)
- j1.lesson03.xml を右クリックして 「実行」の中にある「1 Ant ビルド」を選択
- Jtaf ウィンドウが開いたら、「ファイル」メニューから「Adder に対する骨格テスト」を選択し実行する。
骨格テストを行った際に緑のバーが表示されれば、外側から見たプログラムの骨格は正しくなっている。
赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「実行」ボタンをクリックする。
メッセージ | 詳細 |
---|---|
クラスが存在しません | j1.lesson03 に Adder クラスが存在していない。パッケージやクラス名を確認 |
クラスがpublicで宣言されていません | class の前に public の指定がない。 |
mainメソッドが存在しません | public static void main(String[]) が存在していない。mainという名前やString[]の部分を確認 |
mainメソッドがpublicで宣言されていません | mainメソッドを作る際に public が抜けている。 |
mainメソッドがstaticで宣言されていません | mainメソッドを作る際に static が抜けている。 |
mainメソッドがvoidで宣言されていません | mainメソッドを作る際に void 以外を指定している。 |
mainメソッドにthrows IOExceptionの指定がありません | mainメソッドを作る際にthrows IOExceptionの指定を行っていない。 |
プログラムの作成
続けて、先ほど作成したAdderクラスのmainメソッドの中身を記述する。
全体的には下記のようなプログラムにする。ただし、一行書くごとにCtrl+Sで保存とコンパイルを行い、常に文法エラーが発生していないことを確認すること。
package j1.lesson03; import java.io.*; public class Adder { public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // 一つ目の整数を入力させる System.out.print("一つ目の整数を入力:"); int input1 = Integer.parseInt(reader.readLine()); // 二つ目の整数を入力させる System.out.print("二つ目の整数を入力:"); int input2 = Integer.parseInt(reader.readLine()); System.out.println("合計は:" + (input1 + input2)); } }
プログラムの実行
作成したプログラムを実行してみる。以下の手順で行う。
- 「Adder.java」の上で右クリック
- メニューが表示されるので、「実行(R)」にマウスカーソルを合わせる
- 「1 Java アプリケーション」をクリック
実行が成功すると、以下のように表示される。
一つ目の整数を入力:
ここで、:の右側をクリックして 100 と入力し、Enterキーを押す。すると、プログラムが少し進んで次のように表示される。
二つ目の整数を入力:
また、:の右側をクリックして 200 と入力し、Enterキーを押す。すると、プログラムは最後まで進んで次のように表示される。
合計は:300
プログラムの一行一行と結果の出力を照らし合わせ、プログラムの挙動を考えてみよ。
機能テスト
ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。
保存時にエラーが出ていなければ、 以下の手順で機能テストを実行する。
- Jtaf ウィンドウの「ファイル」メニューから「Adder に対する機能テスト」を選択し、実行する。
赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「Run」ボタンをクリックする。
以後、「~テストを実行」とあった場合、上記のような手順を踏むことを指すものとする。
メッセージ | 詳細 |
---|---|
余計な入力を待っていると考えられます | コンソール入力を取得する命令を3回以上行っていないか確認 |
次の入力を変換できませんでした (???) | ??? を取得しようとして失敗している。コンソール入力を取得する命令を確認 |
期待された結果と異なります | 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較 (エラーメッセージが出力されているエリアの下のほうにあるバーをスクロールさせれば見ることができる) し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す |
メッセージ | テストの概要 |
---|---|
期待された結果と異なります (00) | 入力が順に 20, 30 |
期待された結果と異なります (01) | 入力が順に -20, -30 |
期待された結果と異なります (02) | 入力が順に -10, 10 |
期待された結果と異なります (03) | 入力が順に 10, -10 |
入力を行うプログラムの失敗例
このあたりは説明不足である (実際に説明すると3週間は楽に要する) と思われるため、間違えたプログラムを書いた際に出力されるエラーメッセージを表記しておく。
コンパイル (保存) 時
コンパイルに失敗すると、eclipseウィンドウ下部の 「問題」 にメッセージが表示される。このメッセージと対策をまとめた。
メッセージ | 対策 |
---|---|
処理されない例外の型 IOException | main(String[] args) 以降に throws IOException がない |
IOException はメソッド main で解決できません | import の指定がない |
reader は解決できません | BufferedReader reader = new ... がない、または位置がおかしい |
~は解決できないか、型ではありません | ~に該当する部分のスペルが間違っている、またはimportの指定がない |
実行時
実行時にエラーが起こると、eclipseウィンドウ下部の 「コンソール」 に赤文字のメッセージが表示される。
状態 | 対策 |
---|---|
入力できない | 入力を取得する命令の直前に System.out.println命令を使用していないか。していれば、クリックすべき位置は出力された文字列の右ではなく、次の行になる |
Exception in thread "main" java.lang.NumberFormatException と表示された | 全角モードで入力していないか、Enterキーを押しすぎていないかなどを確認 |
解説
解説のために、プログラムに行番号をつけて解説する。
01: package j1.lesson03; 02: 03: import java.io.*; 04: 05: public class Adder { 06: public static void main(String[] args) throws IOException { 07: BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 08: 09: // 一つ目の整数を入力させる 10: System.out.print("一つ目の整数を入力:"); 11: int input1 = Integer.parseInt(reader.readLine()); 12: 13: // 二つ目の整数を入力させる 14: System.out.print("二つ目の整数を入力:"); 15: int input2 = Integer.parseInt(reader.readLine()); 16: 17: System.out.println("合計は:" + (input1 + input2)); 18: } 19: }
各行では次のようなことが行われている。
- 7行目
- コンソールの入力を取得するためのおまじない
- 10行目
- 入力するタイミングをユーザに知らせるために 一つ目の整数を入力: と表示
- 11行目
- int 型の変数 input1 を宣言
- ユーザの入力した整数を input1 に代入
- 14行目
- 入力するタイミングをユーザに知らせるために 二つ目の整数を入力: と表示
- 15行目
- int 型の変数 input2 を宣言
- ユーザの入力した整数を input2 に代入
- 17行目
- 2つの入力した値の合計を出力
上記の例では、input1とinput2を宣言と同時に初期化している。これは必ずしもこの書き方である必要はなく、以下のように書いても良い。
int input1, input2; // 一つ目の整数を入力させる System.out.print("一つ目の整数を入力:"); input1 = Integer.parseInt(reader.readLine()); // 二つ目の整数を入力させる System.out.print("二つ目の整数を入力:"); input2 = Integer.parseInt(reader.readLine());
条件分岐を行うプログラム
コンソールに実数を一つ入力させ、その数が0または正であるか負であるかを判定する。
演習
クラスの作成
以下の手順で、パッケージ「j1.lesson03」に「Sign」クラスを作成する。
- 先ほど作成したパッケージ 「j1.lesson03」の上で右クリック
- マウスカーソルを「新規」に合わせる
- 「クラス」をクリック
- クラス名は Sign とする
- 先と同じ手順でクラスを作成する
mainメソッドの作成
先と同じ手順で、クラス「Sign」内にpublic static void main(String[] args) throws IOException から始まるメソッドを作成する。
このプログラムでも「コンソールからの入力を取得」を行うため、importや throws IOException を忘れないこと。
骨格テスト
ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。
「Sign に対する骨格テスト」 を実行する。
骨格テストを行った際に緑のバーが表示されれば、外側から見たプログラムの骨格は正しくなっている。
赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「Run」ボタンをクリックする。
メッセージ | 詳細 |
---|---|
クラスが存在しません | j1.lesson03 に Sign クラスが存在していない。パッケージやクラス名を確認 |
クラスがpublicで宣言されていません | class の前に public の指定がない。 |
mainメソッドが存在しません | public static void main(String[]) が存在していない。mainという名前やString[]の部分を確認 |
mainメソッドがpublicで宣言されていません | mainメソッドを作る際に public が抜けている。 |
mainメソッドがstaticで宣言されていません | mainメソッドを作る際に static が抜けている。 |
mainメソッドがvoidで宣言されていません | mainメソッドを作る際に void 以外を指定している。 |
mainメソッドにthrows IOExceptionの指定がありません | mainメソッドを作る際にthrows IOExceptionの指定を行っていない。 |
プログラムの作成
続けて、先ほど作成したSignクラスのmainメソッドの中身を記述する。
全体的には下記のようなプログラムにする。ただし、一文書くごとにCtrl+Sで保存とコンパイルを行い、常に文法エラーが発生していないことを確認すること。
「一行書くごと」ではなく「一文書くごと」と表記しているのは、
if (input == 0)
とだけ書いた時点でコンパイルを行うと、ifの条件が成立した際に実行する命令がないため、エラーとなってしまうからである。そのため、論理的なまとまりを書くごとに保存とコンパイルを行うこと。つまり、
if (input == 0)
とかいたら、それに続く命令も一緒に書いた後、保存とコンパイルを行う。
package j1.lesson03; import java.io.*; public class Sign { public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // 実数を入力させる System.out.print("値を入力:"); double input = Double.parseDouble(reader.readLine()); if (input == 0) { System.out.println("入力された値は0"); } else if (input > 0) { System.out.println("入力された値は正の値"); } else { System.out.println("入力された値は負の値"); } } }
プログラムの実行
先と同じ手順でプログラムを実行する。
実行が成功すると、以下のように表示される。
値を入力:
ここで、:の右側をクリックして 0.0 と入力し、Enterキーを押す。すると、プログラムは最後まで進んで次のように表示される。
入力された値は0
このようなプログラムをテストする場合、すべての命令を実行して網羅する必要がある。上記のプログラムでは一回の実行ですべての命令を網羅することはできないため、最低でも3回の実行を試してみる必要がある。
適切な入力を考え、それぞれ以下の出力も確認せよ。
入力された値は正の値
入力された値は負の値
機能テスト
ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。
「Sign に対する機能テスト」 を実行する。
赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「Run」ボタンをクリックする。
メッセージ | 詳細 |
---|---|
余計な入力を待っていると考えられます | コンソール入力を取得する命令を2回以上行っていないか確認 |
次の入力を変換できませんでした (???) | ??? を取得しようとして失敗している。コンソール入力を取得する命令を確認 |
期待された結果と異なります | 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較 (エラーメッセージが出力されているエリアの下のほうにあるバーをスクロールさせれば見ることができる) し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す |
機能テスト失敗時のヒント
メッセージ | テストの概要 |
---|---|
期待された結果と異なります (Zero) | 入力が 0 |
期待された結果と異なります (Plus) | 入力が 1 |
期待された結果と異なります (PlusGen) | 入力が 10 |
期待された結果と異なります (Minus) | 入力が -1 |
期待された結果と異なります (MinusGen) | 入力が -10 |
期待された結果と異なります (Double) | 入力が 1.0e-10 |
解説
解説のために、プログラムに行番号をつけて解説する。
01: package j1.lesson03; 02: 03: import java.io.*; 04: 05: public class Sign { 06: public static void main(String[] args) throws IOException { 07: BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 08: 09: // 実数を入力させる 10: System.out.print("値を入力:"); 11: double input = Double.parseDouble(reader.readLine()); 12: 13: if (input == 0) { 14: System.out.println("入力された値は0"); 15: } 16: else if (input > 0) { 17: System.out.println("入力された値は正の値"); 18: } 19: else { 20: System.out.println("入力された値は負の値"); 21: } 22: } 23: }
各行では次のようなことが行われている。
- 7行目
- コンソールの入力を取得するためのおまじない
- 10行目
- 入力するタイミングをユーザに知らせるために 値を入力: と表示
- 11行目
- double 型の変数 input を宣言
- ユーザの入力した実数を input に代入
- 13行目
- input の中身が 0 と等しいかどうかで分岐
- input の中身が 0 なら、14行目を実行
- そうでなければ、16行目を実行
- 14行目 (input == 0)
- 入力された値は0 と表示
- 22行目 (ifに続くelseの終了) までジャンプ (プログラムの終了)
- 16行目
- input の中身が 0 より大きいかどうかで分岐
- input の中身が 0 より大きいならば17行目を実行
- そうでなければ19行目を実行
- 17行目
- 入力された値は正の値 と表示
- 22行目 (ifに続くelseの終了) までジャンプ (プログラムの終了)
- 19行目
- ここにきた場合は、この行から始まるブロックを実行 (ブロック内に1命令しかないので、20行目のみを実行)
- 20行目
- 入力された値は負の値 と表示
補足
- 22行目 (ifに続くelseの終了) までジャンプ (プログラムの終了)
とあるが、理解しにくい場合は、次のようにif-elseの連鎖を書き換えてみるとよい
if (input == 0) { System.out.println("入力された値は0"); } else { if (input > 0) { System.out.println("入力された値は正の値"); } else { System.out.println("入力された値は負の値"); } }
if (input == 0) に対応するelseは16行目のelseだが、この条件式 が false になったときに実行される命令は、16行目のif文だけではなく16行目から始まるif-else 全体 である。
わからなくなった場合は、ブロックでくくってみるとわかりやすい。