下準備
テストドライバの導入
第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
これにより、階乗の定義と等しい式が完成した。