第04週目演習

下準備

テストドライバの導入

第04回目分のテストドライバを導入する。以下の手順で行う。

  1. ダウンロード のページを開く (ここをクリック)
  2. プロジェクト「java20XX」にある「test」の左側の「+」をクリック
  3. ツリーが展開されるので「install-libraries.xml」を右クリック
  4. 「実行(R)」にマウスカーソルを合わせる
  5. 「1 Ant ビルド」をクリック
  6. 「コンソール」タブに"BUILD SUCCESSFUL"と表示されれば成功
  7. eclipseの画面でプロジェクト「java20XX」を右クリック
  8. メニューが表示されるので、「更新」あるいは「最新表示」をクリック
  9. "week04.zip" をデスクトップなどにダウンロード
  10. eclipseの画面でプロジェクト「java20XX」を右クリック
  11. メニューから「インポート(I)」を選択
  12. 「インポート」ウィンドウが表示されるので、「Zip ファイル」あるいは「アーカイブファイル」を選択
  13. 「次へ(N)」をクリック
  14. 宛先フォルダー(L): が「java20XX」になっていることを確認
  15. From archive file: の右側にある 「参照(R)...」あるいは「ブラウズ(R)...」をクリック
  16. ファイルダイアログが表示されるので、ダイアログ内に表示されたダウンロードしたファイルをダブルクリック
  17. 前の画面に戻るので、From archive file: のエリアに正しいパスが入力されていることを確認
  18. フォルダ「/」の左にチェックがついていることを確認 (ついていなければチェックボックスをクリック)
  19. 「警告を出さずに既存リソースを上書き」にチェックがついていることを確認 (上書きしたくないファイルがある場合はチェックを外す)
  20. 「終了 (F)」をクリック

第04週目テストドライバの導入に成功すると、java20XX プロジェクトの test フォルダに j1.lesson04.xml というファイルが作成される。

パッケージの作成

過去の演習を参考にして、「j1.lesson04」というパッケージを作成する。

指定した回数だけ表示を行うプログラム

コンソールに整数を一つ入力させ、その数だけ「Hello!」と表示する。ただし、0未満が指定された場合は、「繰り返す回数には0以上を入れてください。」とだけ表示する。

演習

クラスの作成

以下の手順で、パッケージ「j1.lesson04」に「LoopPrint」クラスを作成する。

  1. 先ほど作成したパッケージ 「j1.lesson04」の上で右クリック
  2. マウスカーソルを「新規」に合わせる
  3. 「クラス」をクリック
  4. クラス名は LoopPrint とする
  5. 先週までと同じ手順でクラスを作成する

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: }

階乗を計算し表示するプログラム

コンソールに整数を一つ入力させ、その数の階乗を計算し表示する。ただし、0未満が指定された場合は、「未定義です」とだけ表示する。

ただし、階乗(n!)は次の式で表される。

0! = 1
1! = 1
2! = 2 * 1
3! = 3 * 2 * 1
n! = n * n - 1 * .. * 1

演習

クラスの作成

以下の手順で、パッケージ「j1.lesson04」に「Factorial」クラスを作成する。

  1. 先ほど作成したパッケージ 「j1.lesson04」の上で右クリック
  2. マウスカーソルを「新規」に合わせる
  3. 「クラス」をクリック
  4. クラス名は Factorial とする
  5. 先週までと同じ手順でクラスを作成する

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: }

繰り返し部分を簡単に解説すると、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

これにより、階乗の定義と等しい式が完成した。