第08週目演習

下準備

テストドライバの導入

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

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

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

パッケージの作成

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

演習の前に

先週と同様に、main以外のメソッドについても骨格テストが行われる。
骨格テストは、「クラスとその中に必要な全てのメソッドを宣言した後」に実行する。

また、それぞれのメソッドが単独で呼び出された際に、正しい動作を行ってくれるかどうかを調べる単体テストも実行する。このテストによって、どのメソッド内で問題が発生したかなど、プログラムの誤りをより特定しやすくなる。

戻り値を持ったメソッドを使ったプログラム

main以外のメソッドを用い、より効率のよいプログラムを作成する。メソッドを呼び出して、返ってくる値を操作する。

演習

クラスの作成

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

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

mainメソッドの作成

クラス「AddSub」内にpublic static void main(String[] args) から始まるメソッドを作成する。

add メソッドの作成

クラス「AddSub」内に 「add」という名前を持ち、仮引数に2つのint型の変数をとるメソッドを作成する。また、メソッドの戻り値はintとする。骨格だけでよいのでメソッドの中身は空でよい。

仮引数の名前は何でも良いが、ここでは順に a, b という名前をつけることにする。

sub メソッドの作成

クラス「AddSub」内に 「sub」という名前を持ち、仮引数に2つのint型の変数をとるメソッドを作成する。また、メソッドの戻り値はintとする。骨格だけでよいのでメソッドの中身は空でよい。

仮引数の名前は何でも良いが、ここでは順に a, b という名前をつけることにする。

全体の骨格

ここまでのプログラムの骨格は以下のようになる。

package j1.lesson08;

public class AddSub {

    public static void main(String[] args) {
    }
    
    public static int add(int a,int b) {
        return 0;
    }
    
    public static int sub(int a,int b) {
        return 0;
    }
}

main メソッドのほかに、add,sub メソッドを作成している。その際、戻り値が void 型でないメソッドは、return文を入れないとコンパイルエラーになるため、ダミーの戻り値を用意している。

骨格テスト

ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。

「AddSub に対する骨格テスト」 を実行する。

骨格テストを行った際に緑のバーが表示されれば、外側から見たプログラムの骨格は正しくなっている。

赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「実行」ボタンをクリックする。

メッセージ 詳細
(クラス名), existence j1.lesson08 に AddSub クラスが存在していない。パッケージやクラス名を確認
(メソッド名), existence 指定されたメソッドが存在しない
(メソッド名), public メソッドを作る際に public が抜けている
(メソッド名), static メソッドを作る際に static が抜けている
(メソッド名), type <T> メソッドを作る際に戻り値の型を間違えている (正しくは <T>)

メソッドの実装 (add)

メソッド add を実装する。このメソッドは、実行されると、仮引数であるaとbを足した値を返す。

public static int add(int a, int b) {
    return a + b;
}

メソッドの実装 (sub)

メソッド sub を実装する。このメソッドは、実行されると、仮引数であるaからbを引いた値を返す。

public static int sub(int a, int b) {
    return a - b;
}

単体テスト

ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。

mainメソッド内に各メソッドを呼び出すプログラムを書いてみる。例えば以下の様な形。

public static void main(String[] args) {
  System.out.println(add(1, 2));
  System.out.println(sub(10, 7));
}

このプログラムを実行し、各メソッドが期待通りに動いていることを確認する。確認したら、mainメソッドの中身は空にして良い。

「AddSub に対する単体テスト」 を実行する。

単体テストを行った際に緑のバーが表示されれば、各メソッドはある程度正しく作成されていると思われる。

赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「実行」ボタンをクリックする。

メッセージ 詳細
(メソッド名), 期待された結果と異なります (メソッド名)を起動した結果が期待された結果と異なる。下記のテスト項目を参照

テスト項目は以下の通りである。

項目名 詳細
testSimple_add add(int,int) を起動
testSimple_sub sub(int,int) を起動

main メソッドの実装

続けて、先ほど作成した AddSub クラスのmainメソッドの中身を記述する。mainメソッドでは、add、subを呼び出して、戻り値を表示する。そして、同時に2つのメソッドを呼び出したときの戻り値を表示する。

全体的には下記のようなプログラムにする。ただし、一文書くごとにCtrl+Sで保存とコンパイルを行い、常に文法エラーが発生していないことを確認すること。

package j1.lesson08;

public class AddSub {

   public static void main(String[] args) {
       // 1 + 2
       System.out.println(add(1, 2));
       
       // 10 - 7
       System.out.println(sub(10, 7));
       
       // (1 + 2) - (3 - 4)
       System.out.println(sub(add(1, 2), sub(3, 4)));
   }
   
   public static int add(int a, int b) {
       return a + b;
   }
   
   public static int sub(int a, int b) {
       return a - b;
   }
}

プログラムの実行

先週までと同じ手順でプログラムを実行する。

実行が成功すると、以下のように表示される。

3
3
4

機能テスト

ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。

「AddSub に対する機能テスト」 を実行する。

赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「実行」ボタンをクリックする。

メッセージ 詳細
期待された結果と異なります 出力された結果が期待された値と異なる。

機能テストの項目

項目名 テストの内容
testRun プログラムを実行

解説

解説のために、プログラムに行番号をつけて解説する。

01: package j1.lesson08;
02: 
03: public class AddSub {
04: 
05:    public static void main(String[] args) {
06:        // 1 + 2
07:        System.out.println(add(1, 2));
08:        
09:        // 10 - 7
10:        System.out.println(sub(10, 7));
11:        
12:        // (1 + 2) - (3 - 4)
13:        System.out.println(sub(add(1, 2), sub(3, 4)));
14:    }
15:    
16:    public static int add(int a, int b) {
17:        return a + b;
18:    }
19:    
20:    public static int sub(int a, int b) {
21:        return a - b;
22:    }
23: }

戻り値を持つメソッドの中で戻り値を持つメソッドを呼び出すプログラム

10人の中から2人選ぶ組み合わせ(10C2)を計算して表示する。

演習

クラスの作成

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

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

main メソッドの作成

クラス「Combination」内にpublic static void main(String[] args) から始まるメソッドを作成する。

combination メソッドの作成

クラス「Combination」内に「combination」という名前を持ち、仮引数に2つのint型の変数をとるメソッドを作成する。また、メソッドの戻り値はintとする。骨格だけでよいのでメソッドの中身は空でよい。

仮引数の名前は何でも良いが、ここでは順に n, r という名前をつけることにする。

fact メソッドの作成

クラス「Combination」内に「fact」という名前を持ち、仮引数に1つのint型の変数をとるメソッドを作成する。また、メソッドの戻り値はintとする。骨格だけでよいのでメソッドの中身は空でよい。

仮引数の名前は何でも良いが、ここでは n という名前をつけることにする。

全体の骨格

ここまでのプログラムの骨格は以下のようになる。どんなものを作成するかイメージを与えるため、コメントをつけている。

package j1.lesson08;

public class Combination {

    public static void main(String[] args) {
        // 10C2 の計算結果を表示
    }
    
    // nCr を計算するメソッド
    public static int combination(int n, int r) {
        return 0;
    }
    
    // nの階乗を計算するメソッド
    public static int fact(int n) {
        return 0;
    }
}

main メソッドのほかに、combination,fact メソッドを作成している。先ほどと同様に、戻り値の型が void でないメソッドにはダミーの値を返す return 文を挿入している。

骨格テスト

ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。

「Combination に対する骨格テスト」 を実行する。

骨格テストを行った際に緑のバーが表示されれば、外側から見たプログラムの骨格は正しくなっている。

赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「実行」ボタンをクリックする。

メッセージ 詳細
(クラス名), existence j1.lesson08 に Combination クラスが存在していない。パッケージやクラス名を確認
(メソッド名), existence 指定されたメソッドが存在しない
(メソッド名), public メソッドを作る際に public が抜けている
(メソッド名), static メソッドを作る際に static が抜けている
(メソッド名), type int メソッドを作る際に int 以外を指定している

メソッドの実装 (combination)

メソッド combination を実装する。このメソッドは、与えられた 2 つの整数 n,r に対して、nCrを以下のように計算し、値を返すメソッドである。

nCr = n! / ((n-r)! * r!)
public static int combination(int n, int r) {
       return fact(n) / (fact(n-r) * fact(r));
}

メソッドの実装 (fact)

メソッド fact を実装する。このメソッドは、与えられた 1 つの整数に対して、その階乗の値を以下のように計算し、値を返すメソッドである。

n! = n * (n-1) * .. * 1
public static int fact(int n) {
       int total = 1;
       for (int i = n; i >= 1; i--) {
           total *= i;
       }
       return total;
}

単体テスト

ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。

mainメソッド内に各メソッドを呼び出すプログラムを書いてみる。例えば以下の様な形。

public static void main(String[] args) {
  System.out.println(fact(10));
  System.out.println(combination(4, 2));
}

このプログラムを実行し、各メソッドが期待通りに動いていることを確認する。確認したら、mainメソッドの中身は空にして良い。

「Combination に対する単体テスト」 を実行する。

単体テストを行った際に緑のバーが表示されれば、各メソッドはある程度正しく作成されていると思われる。

赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「実行」ボタンをクリックする。

メッセージ 詳細
(メソッド名), 期待された結果と異なります (メソッド名)を起動した結果が期待された結果と異なる。下記のテスト項目を参照

テスト項目は以下の通りである。

項目名 詳細
testFact_1 fact(int) を (1) で起動
testFact_2 fact(int) を (2) で起動
testFact_3 fact(int) を (3) で起動
testFact_10 fact(int) を (10) で起動
testCombination_1_1 combination(int,int) を (1,1) で起動
testCombination_3_1 combination(int,int) を (3,1) で起動
testCombination_4_2 combination(int,int) を (4,2) で起動
testCombination_5_3 combination(int,int) を (5,3) で起動

プログラムの作成

続けて、先ほど作成したCombinationクラスのmainメソッドの中身を記述する。main メソッドでは、10人から2人選ぶ組み合わせ(102)を計算して表示する。

全体的には下記のようなプログラムにする。ただし、一文書くごとにCtrl+Sで保存とコンパイルを行い、常に文法エラーが発生していないことを確認すること。

package j1.lesson08;

public class Combination {

   public static void main(String[] args) {
     //combinationメソッドを呼び出す
       System.out.println("10人から2人選ぶ組み合わせは" + combination(10, 2) + "通り");
   }
   
   // nCr = n! / ((n-r)! * r!)を計算するメソッド
   public static int combination(int n, int r) {
   	// 階乗の計算でfactメソッドを呼び出す
       return fact(n) / (fact(n-r) * fact(r));
   }
   
  //nの階乗を計算するメソッド
   public static int fact(int n) {
       int total = 1;
       for (int i = n; i >= 1; i--) {
           total *= i;
       }
       return total;
   }
}

プログラムの実行

先週までと同じ手順でプログラムを実行する。

実行が成功すると、以下のように表示される。

10人から2人選ぶ組み合わせは45通り

機能テスト

ここまでの作業をCtrl+Sを押して保存し、コンパイルを行う (保存時に自動で行われる)。ここでエラーが発生していたら文法エラーなので見直す。

「Combination に対する機能テスト」 を実行する。

赤いバーが表示された場合、メッセージを元にプログラムを見直すこと。修正を行い、Ctrl+Sで保存した後に「実行」ボタンをクリックする。

メッセージ 詳細
無限ループの可能性 繰り返し部分が無限に繰り返されていないか確認
期待された結果と異なります 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較 (エラーメッセージが出力されているエリアの下のほうにあるバーをスクロールさせれば見ることができる) し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す

機能テスト失敗時のヒント

メッセージ 詳細
期待された結果と異なります 出力された結果が期待された値と異なる。

機能テストの項目

項目名 テストの内容
testRun プログラムを実行

解説

解説のために、プログラムに行番号をつけて解説する。

01: package j1.lesson08;
02: 
03: public class Combination {
04: 
05:    public static void main(String[] args) {
06:      //combinationメソッドを呼び出す
07:        System.out.println("10人から2人選ぶ組み合わせは" + combination(10, 2) + "通り");
08:    }
09:    
10:    // nCr = n! / ((n-r)! * r!)を計算するメソッド
11:    public static int combination(int n, int r) {
12:        // 階乗の計算でfactメソッドを呼び出す
13:        return fact(n) / (fact(n-r) * fact(r));
14:    }
15:    
16:   //nの階乗を計算するメソッド
17:    public static int fact(int n) {
18:        int total = 1;
19:        for (int i = n; i >= 1; i--) {
20:            total *= i;
21:        }
22:        return total;
23:    }
24: }

なお、13行目の計算ははじめから約分することによって高速に計算できる。