下準備
テストドライバの導入
第04回目分のテストドライバを導入する。以下の手順で行う。
- ダウンロード のページを開く (ここをクリック)
- プロジェクト「java20XX」にある「test」の左側の「+」をクリック
- ツリーが展開されるので「install-libraries.xml」を右クリック
- 「実行(R)」にマウスカーソルを合わせる
- 「1 Ant ビルド」をクリック
- 「コンソール」タブに"BUILD SUCCESSFUL"と表示されれば成功
- eclipseの画面でプロジェクト「java20XX」を右クリック
- メニューが表示されるので、「更新」あるいは「最新表示」をクリック
- "week04.zip" をデスクトップなどにダウンロード
- eclipseの画面でプロジェクト「java20XX」を右クリック
- メニューから「インポート(I)」を選択
- 「インポート」ウィンドウが表示されるので、「Zip ファイル」あるいは「アーカイブファイル」を選択
- 「次へ(N)」をクリック
- 宛先フォルダー(L): が「java20XX」になっていることを確認
- From archive file: の右側にある 「参照(R)...」あるいは「ブラウズ(R)...」をクリック
- ファイルダイアログが表示されるので、ダイアログ内に表示されたダウンロードしたファイルをダブルクリック
- 前の画面に戻るので、From archive file: のエリアに正しいパスが入力されていることを確認
- フォルダ「/」の左にチェックがついていることを確認 (ついていなければチェックボックスをクリック)
- 「警告を出さずに既存リソースを上書き」にチェックがついていることを確認 (上書きしたくないファイルがある場合はチェックを外す)
- 「終了 (F)」をクリック
第04週目テストドライバの導入に成功すると、java20XX プロジェクトの test フォルダに j1.lesson04.xml というファイルが作成される。
パッケージの作成
過去の演習を参考にして、「j1.lesson04」というパッケージを作成する。
指定した回数だけ表示を行うプログラム
コンソールに整数を一つ入力させ、その数だけ「Hello!」と表示する。ただし、0未満が指定された場合は、「繰り返す回数には0以上を入れてください。」とだけ表示する。
演習
クラスの作成
以下の手順で、パッケージ「j1.lesson04」に「LoopPrint」クラスを作成する。
- 先ほど作成したパッケージ 「j1.lesson04」の上で右クリック
- マウスカーソルを「新規」に合わせる
- 「クラス」をクリック
- クラス名は LoopPrint とする
- 先週までと同じ手順でクラスを作成する
mainメソッドの作成
先と同じ手順で、クラス「LoopPrint」内にpublic static void main(String[] args) throws IOException から始まるメソッドを作成する。
このプログラムでは「コンソールからの入力を取得」を行うため、importや throws IOException を忘れないこと。
骨格テスト
ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。
「LoopPrint に対する骨格テスト」 を実行する。
骨格テストを行った際に緑のバーが表示されれば、外側から見たプログラムの骨格は正しくなっている。
赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「Run」ボタンをクリックする。
メッセージ | 詳細 |
---|---|
クラスが存在しません | j1.lesson04 に LoopPrint クラスが存在していない。パッケージやクラス名を確認 |
クラスが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の指定を行っていない。 |
プログラムの作成
続けて、先ほど作成したLoopPrintクラスのmainメソッドの中身を記述する。
全体的には下記のようなプログラムにする。ただし、一文書くごとにCtrl+Sで保存とコンパイルを行い、常に文法エラーが発生していないことを確認すること。
package j1.lesson04; import java.io.*; public class LoopPrint { public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.print("繰り返す回数を入力してください:"); int count = Integer.parseInt(reader.readLine()); // 0回未満の繰り返しはエラー if (count < 0) { System.out.println("繰り返す回数には0以上を入れてください。"); } else { // i が 0 から count - 1 まで繰り返す for (int i = 0; i < count; i++) { System.out.println("Hello!"); } } } }
プログラムの実行
先週までと同じ手順でプログラムを実行する。
実行が成功すると、以下のように表示される。
繰り返す回数を入力してください:
ここで、:の右側をクリックして 3 と入力し、Enterキーを押す。すると、プログラムは最後まで進んで次のように表示される。
Hello! Hello! Hello!
機能テスト
ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。
「LoopPrint に対する機能テスト」 を実行する。
赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「Run」ボタンをクリックする。
メッセージ | 詳細 |
---|---|
余計な入力を待っていると考えられます | コンソール入力を取得する命令を2回以上行っていないか確認 |
次の入力を変換できませんでした (???) | ??? を取得しようとして失敗している。コンソール入力を取得する命令を確認 |
期待された結果と異なります | 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較 (エラーメッセージが出力されているエリアの下のほうにあるバーをスクロールさせれば見ることができる) し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す |
機能テスト失敗時のヒント
メッセージ | テストの内容 |
---|---|
期待された結果と異なります (M5) | 入力が-5 |
期待された結果と異なります (M1) | 入力が-1 |
期待された結果と異なります (0) | 入力が0 |
期待された結果と異なります (1) | 入力が1 |
期待された結果と異なります (5) | 入力が5 |
解説
解説のために、プログラムに行番号をつけて解説する。
01: package j1.lesson04; 02: 03: import java.io.*; 04: 05: public class LoopPrint { 06: 07: public static void main(String[] args) throws IOException { 08: BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 09: System.out.print("繰り返す回数を入力してください:"); 10: int count = Integer.parseInt(reader.readLine()); 11: 12: // 0回未満の繰り返しはエラー 13: if (count < 0) { 14: System.out.println("繰り返す回数には0以上を入れてください。"); 15: } 16: else { 17: // i が 0 から count - 1 まで繰り返す 18: for (int i = 0; i < count; i++) { 19: System.out.println("Hello!"); 20: } 21: } 22: } 23: }
- 8行目
- コンソールの入力を取得するためのおまじない
- 9行目
- 入力するタイミングをユーザに知らせるために 繰り返す回数を入力してください: と表示
- 10行目
- int 型の変数 count を宣言
- ユーザの入力した整数を count に代入
- 13行目
- count の中身が 0 未満かどうかで分岐
- count の中身が 0 未満なら、14行目以降を実行
- そうでなければ、16行目以降を実行
- 14行目
- 繰り返す回数が0回未満なので、繰り返す回数には0以上を入れてください。 と表示
- 21行目 (ifに続くelseの終了) までジャンプ (プログラムの終了)
- 16行目
- この行から始まるブロックを実行 (17行目以降を実行)
- 18行目
- 以下の条件で繰り返しを開始する
- int 型の変数 i を宣言し、初期値を0に設定する
- 毎回の繰り返しの最初に i < count が成立するか調べ、成立しなければ繰り返しを終了する (21行目へジャンプ)
- 毎回の繰り返しの最後に、iの値を1だけ増やす
- 19行目 (18行目から始まるforループの中身)
- Hello! と表示
- 21行目
- (プログラムの終了)
階乗を計算し表示するプログラム
コンソールに整数を一つ入力させ、その数の階乗を計算し表示する。ただし、0未満が指定された場合は、「未定義です」とだけ表示する。
ただし、階乗(n!)は次の式で表される。
0! = 1 1! = 1 2! = 2 * 1 3! = 3 * 2 * 1 n! = n * n - 1 * .. * 1
演習
クラスの作成
以下の手順で、パッケージ「j1.lesson04」に「Factorial」クラスを作成する。
- 先ほど作成したパッケージ 「j1.lesson04」の上で右クリック
- マウスカーソルを「新規」に合わせる
- 「クラス」をクリック
- クラス名は Factorial とする
- 先週までと同じ手順でクラスを作成する
mainメソッドの作成
先と同じ手順で、クラス「Factorial」内にpublic static void main(String[] args) throws IOException から始まるメソッドを作成する。
このプログラムでは「コンソールからの入力を取得」を行うため、importや throws IOException を忘れないこと。
骨格テスト
ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。
「Factorial に対する骨格テスト」 を実行する。
骨格テストを行った際に緑のバーが表示されれば、外側から見たプログラムの骨格は正しくなっている。
赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「実行」ボタンをクリックする。
メッセージ | 詳細 |
---|---|
クラスが存在しません | j1.lesson04 に Factorial クラスが存在していない。パッケージやクラス名を確認 |
クラスが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の指定を行っていない。 |
プログラムの作成
続けて、先ほど作成したFactorialクラスのmainメソッドの中身を記述する。
全体的には下記のようなプログラムにする。ただし、一文書くごとにCtrl+Sで保存とコンパイルを行い、常に文法エラーが発生していないことを確認すること。
package j1.lesson04; import java.io.*; public class Factorial { public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.print("整数を入力:"); int n = Integer.parseInt(reader.readLine()); if (n < 0) { System.out.println("未定義です"); } else { // 乗算の単位元は 1 int factorial = 1; for (int i = n; i >= 1; i--) { factorial *= i; } System.out.println(n + "の階乗は" + factorial); } } }
プログラムの実行
先週までと同じ手順でプログラムを実行する。
実行が成功すると、以下のように表示される。
整数を入力:
ここで、:の右側をクリックして 10 と入力し、Enterキーを押す。すると、プログラムは最後まで進んで次のように表示される。
10の階乗は3628800
機能テスト
ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。
「Factorial に対する機能テスト」 を実行する。
赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「実行」ボタンをクリックする。
メッセージ | 詳細 |
---|---|
余計な入力を待っていると考えられます | コンソール入力を取得する命令を2回以上行っていないか確認 |
次の入力を変換できませんでした (???) | ??? を取得しようとして失敗している。コンソール入力を取得する命令を確認 |
期待された結果と異なります | 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較 (エラーメッセージが出力されているエリアの下のほうにあるバーをスクロールさせれば見ることができる) し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す |
機能テスト失敗時のヒント
メッセージ | テストの内容 |
---|---|
期待された結果と異なります (M5) | 入力が-5 |
期待された結果と異なります (M1) | 入力が-1 |
期待された結果と異なります (0) | 入力が0 |
期待された結果と異なります (1) | 入力が1 |
期待された結果と異なります (2) | 入力が2 |
期待された結果と異なります (5) | 入力が5 |
期待された結果と異なります (10) | 入力が10 |
解説
解説のために、プログラムに行番号をつけて解説する。
01: package j1.lesson04; 02: 03: import java.io.*; 04: 05: public class Factorial { 06: public static void main(String[] args) throws IOException { 07: BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 08: System.out.print("整数を入力:"); 09: int n = Integer.parseInt(reader.readLine()); 10: 11: if (n < 0) { 12: System.out.println("未定義です"); 13: } 14: else { 15: // 乗算の単位元は 1 16: int factorial = 1; 17: for (int i = n; i >= 1; i--) { 18: factorial *= i; 19: } 20: System.out.println(n + "の階乗は" + factorial); 21: } 22: } 23: }
- 7行目
- コンソールの入力を取得するためのおまじない
- 8行目
- 入力するタイミングをユーザに知らせるために 整数を入力: と表示
- 9行目
- int 型の変数 n を宣言
- ユーザの入力した整数を n に代入
- 11行目
- n の中身が 0 未満かどうかで分岐
- n の中身が 0 未満なら、12行目以降を実行
- そうでなければ、14行目以降を実行
- 12行目
- 0未満に対する階乗は定義されていないので、 未定義です と表示
- 21行目までジャンプ (プログラムの終了)
- 14行目
- else にぶら下がっているブロックの中身を実行 (15行目以降を実行)
- 16行目
- int型の変数 factorial を宣言
- factorialの中身を 1 で初期化 (1は掛け算の単位元である)
- 16行目
- int型の変数 factorial を宣言
- factorialに1を代入
- 17行目
- 以下の条件で繰り返しを開始する
- int 型の変数 i を宣言し、初期値を n (ユーザの入力した整数) に設定する
- 毎回の繰り返しの最初に i >= 1 が成立するか調べ、成立しなければ繰り返しを終了する (20行目へジャンプ)
- 毎回の繰り返しの最後に、iの値を1だけ減らす
- 18行目 (17行目から始まるforループの中身)
- factorialにiの値を掛けたものをfactorialへ代入
- 20行目
- 以下を結合したものを表示
- n (ユーザの入力した整数)
- 文字列 "の階乗は"
- factorial (nの階乗を計算したもの)
- (プログラムの終了)
繰り返し部分を簡単に解説すると、18行目は繰り返しによって以下の計算が行われている。
繰り返し1回目: factorial *= n // (iの初期値) 繰り返し2回目: factorial *= n - 1 繰り返し3回目: factorial *= n - 2 ... 繰り返しn回目: factorial *= 1
factorialの初期値は16行目で1に設定されているので、結果は以下のようになる。
factorial = 1 * n * (n - 1) * (n - 2) * ... * 1
先頭の 1 は掛け算の単位元であり、いくら掛けても結果に影響を及ぼさない。つまり、以下の式になる。
factorial = n * (n - 1) * (n - 2) * ... * 1
これにより、階乗の定義と等しい式が完成した。