Java Mid Basic 〜Lv2_2_Javaの基本(リファクタリング)ゲームループ付き〜

イントロダクション

前回は、四則計算を行うプログラム(ゲームループ付き)を作成しました。

しかし問題が。。。

このプログラムには致命的なバグがあります。これは計算結果をセットする変数が「int型」のため割り算の結果も整数になっていることです。本当は「少数」の答えが入るはずです。
つまり4 / 3 = 1.33333 ...の時に答えが「1」というのは間違いで、「1.33333 ...」というのが正しいということです。

もう少しいうならば、int型の変数にセットした時点で、小数点以下の値が切り捨てられマス。JVMがやってくれるようです。

四則演算の解説

プログラムのコードは別物ですが、わかりやすいと思います。

ここでJUnit

JUnitというのは、テスト用のフレームワークです。これを使用すると、メソッドに「@Test」とつけるだけでテストとして実行することができます。

問題に関して

上ような細かい部分に関しては、Javaに長く触っている人間(自分)でもよくわかっていない部分があります。
それは、「4 /3」の答えはdouble型で表示したらどうなるか?です。※小数点以下が何桁表示されるか?がわからない。。。
なのでテストして見ます。「テストクラス」という言葉を前回使用しましたが、その部分には触れませんでした。
前回作成したテストクラスは実装したクラスと同じ名前になっています。名前になっています。これはよろしくないので以下のように作成しました。そして小数点で表示されない原因を探るべくJUnitテストを実行しました。

下の動画と、連動していませんが、具体的には次のような名前です。

項目 クラス名
テストするクラスの名前 Sammple
テストクラスの名前 SampleTest

JUnitクラス

色々試した結果「割り算を行うときには(答えが小数点になるときは)」計算する値も小数点で計算する必要がある」という結論に至り、「割り算のときは数値を小数(double)で扱う」という仕様を追加することにしました。以下のようなコードになるということです。

// 割り算の場合
double sahenDouble = sahen;
double uhenDouble = uhen;
ansDouble = sahenDouble  / uhenDouble ;

つまり、割り算のときは「小数」を使用するということです。
そしてそれをコードにしたのがGitにアップしてあります。初めのコードと比較された形で閲覧することができると思います。

リファクタリング準備

そして、ソースが汚いのでこれを綺麗にしてやる必要があります。そのために必要なテクニックが「メソッドを作成する」です。「え?そんなのわかるけど?」と思った方はスキありで一本取られます(笑)

メソッドの作り方

先ほどの通りに「メソッドの書き方」は今までに説明しているのでわかると思います。

どーゆーことか?

「メソッドを作るのはなぜか?」という問いに答える事が必要だということです。現状のコードは汚いです。
何を持って「キレイ」「キタナい」の判断をするのか?は今後理解して行けば良いと思いますが、現状では「同じようなコードを何度も書いている」というところが「キタナい」というとこに着眼して話を進めます。というか問題(クエスチョン)にしようと思います。

問題

Gitにあるソースの話をします。switch文が何度も出てきているのでこれをなんとかしたいと思っています。どーしたら良いでしょうか?※つまり長ったらしいコードでスッキリしていないので「キタナイ」というわけです。

ヒント:メソッドを作れば良いのです。

<問題のソース>

public String calculate(String fomula) {
    // 計算の記号を判定
    /* 「ここもコメント」
     * 足し算:0 
     * 引き算:1 
     * 掛け算:2 
     * 割り算:3
     */
    int kigo = -1;
    int tashi = fomula.indexOf("+");
    int hiki = fomula.indexOf("-");
    int kake = fomula.indexOf("*");
    int wari = fomula.indexOf("/");

    if (tashi != -1) {
        // 足し算
        kigo = 0;
    } else if (hiki != -1) {
        // 引き算
        kigo = 1;
    } else if (kake != -1) {
        // かけ算
        kigo = 2;
    } else if (wari != -1) {
        // わり算
        kigo = 3;
    } else {
        System.out.println("四則計算の式が不適切です。: " + fomula);
        return "想定外の例外(Exception)のため不明";
    }
    // 計算記号の文字列を初期化(NULLを設定する)
    String calc = null;

    // 入力された式を取り出す
    switch(kigo) {
    case 0:
        calc = "\\+";
        break;
    case 1:
        calc = "\\-";
        break;
    case 2:
        calc = "\\*";
        break;
    case 3:
        calc = "\\/";
        break;
    }
    // 数式から値を取得する
    String[] fomulaArray = fomula.split(calc);
    if (fomulaArray.length != 2) {
        System.out.println("式が不適当です。「1 + 1」のように入力してください。");
        return "想定外の例外(Exception)のため不明";
    }
    // 左の値にあるスペースを削除する
    String leftValue = fomulaArray[0].trim();
    int sahen = Integer.parseInt(leftValue);
    // 右の値にあるスペースを削除する
    String rightValue = fomulaArray[1].trim();
    int uhen = Integer.parseInt(rightValue);
    // 答えの変数を初期化
    int answer = 0;
    // 割り算用の変数
    double ansDouble = 0.0;
    // 計算をする
    switch(kigo) {
    case 0:
        answer = sahen + uhen;
        break;
    case 1:
        answer = sahen - uhen;
        break;
    case 2:
        answer = sahen * uhen;
        break;
    case 3:
        // 割り算の場合
        double sahenDouble = sahen;
        double uhenDouble = uhen;
        ansDouble = sahenDouble  / uhenDouble ;
        break;
    }
    // 三項演算子(記号が3ならばansDoubleを、そうでないならばanswerを文字列に変換
    return kigo == 3 ? String.valueOf(ansDouble) : String.valueOf(answer);
}

でわでわ。。。

<<< 前回 次回 >>>

Java Basic

  1. Java Basic Level 1 Hello Java
  2. Java Basic Level2 Arithmetic Calculate
  3. Java Basic Level3 About String class
  4. Java Basic Level 4Boolean
  5. Java Basic Level 5If Statement
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 Traning of If statement
  8. Java Basic Level8 How to use for statement
  9. Java Basic Level 8.5 Array
  10. Java Basic Level 9Training of for statement
  11. Java Basic Level 10 While statement
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1
  17. Java Basic JUnit 〜テストスイートの作り方〜

Java Mid Basic 〜Lv2_1_Javaの基本(四則計算)ゲームループ付き〜

インントロダクション

前回、四則計算のプログラムを書くと記載しながら以下の内容に関して記載しました。

  1. クラスの作り方
  2. メソッドの書き方
  3. int型とString型の変数

この部分はこれから作成するプログラムを理解するために必要なことなので少し長い記述になりました。

四則計算をする

四則計算は算数でやったのと同じです。というかパソコンをコントロールするのがプログラム→電卓の大きなものをコントロールするので計算方法は電卓と同じです。

<注意>

ただし掛け算に関して「x」ではなく「*」を使用します。そのほか、べき乗など学校で習うような書き方ではなく(パソコンで入力ができない?)「^」キャレットを使用して表現します。

ソースコード

初めに作成したコードはこちらにありますが、これを修正していく形でどんどん大きなことを実装していきます。ちなみにプログラム引数を表示する処理が増えてます。

public class Lv2HelloWorld {
    public static void main(String[] args) {
        // プログラム引数の表示部分
        System.out.println("プログラム引数のサイズ:" + args.length);
        for (int i = 0; i < args.length; i++) {
            System.out.println("プログラム引数:" + args[i]);
        }
        // 標準入力を受ける
        Scanner input = new Scanner(System.in);

        while(true) {
            System.out.print("入力してください: ");
            String inStr = input.nextLine();
            if ("hello".equals(inStr)) {
                System.out.println("Hello World!");
            } else {
                System.out.println("想定外の入力です");
                break;
            }
            System.out.println("Next command ... ");
        }
        System.out.print("AP is fiinished. Bye!");
    }
}

このコードを拡張して四則計算を行うように修正します。
現状では。以下のような処理になっています。

  1. プログラム引数を表示する
  2. 標準入力を受ける(コンソールの入力を取得する)
  3. 入力値が「hello」の場合は「Hello World!」をコンソールに表示
  4. それ以外は「想定外の入力です。」と表示してプログラムを終了する(while文を抜ける)
  5. ループして2まで戻り繰り返す

上記のような処理をしています。このままでは「hello」以外の入力を行えばプログラムが終了してしまうので、ここの部分に、今回の「四則計算を行う」処理を追加します。

具体的に

以下のような処理を行うように設計します(多くの人は頭の中でやってしまいます、プログラムが小さいからです。)。

  1. プログラム引数を表示する
  2. 標準入力を受ける(コンソールの入力を取得する)
  3. 入力値が「hello」の場合は「Hello World!」をコンソールに表示
  4. 入力値が「?」 + 「計算の記号」 + 「?」が入力された時に四則計算を行い、計算結果をコンソールに表示する
  5. それ以外は「想定外の入力です。」と表示してプログラムを終了する(while文を抜ける)
  6. ループして2まで戻り繰り返す

このように設計しました。上の赤い字の部分が追加したところです。
この追加部分の処理について見ていきます。

追加した処理

まずはコード上で追加する部分を明確にします。
設計上では「4」の部分が追加しているところなので処理もその部分を見つけます。

if ("hello".equals(inStr)) {
    System.out.println("Hello World!");
} else {
    System.out.println("想定外の入力です");
    break;
}

の部分がこれにあたりますので、ここに「入力値がXXX」だったら。。。の処理を追加します。

自分の作成した答えはこちらです。プルダウンで開きます。
if ("hello".equals(inStr)) {
    System.out.println("Hello World!");
} else if (inStr.matches("[0-9].*[0-9]")) {
    int answer = myClass.calculate(inStr);
    System.out.println("答えは:" + answer + "です。");
} else {
    System.out.println("想定外の入力です");
    break;
}

IF文で使用している「"[0-9].*[0-9]"」の部分を「[正規表現](http://www.turtle.gr.jp/techno/regular-expression.html)」と呼び文字列に対してルールを強いるものです。
例えば、入力した文字列が「メールアドレスかどうか?」を判定するのにも正規表現を使用します。「XXXX@XXX.XXX」のように一定の文字の並びかたが正規表現で指定したものになっているかどうか?を判定するために使用します。
ここに簡単なサンプルを記載してあります。指定の文字列をから文字に変換(削除)する処理を作成しています。
ちなみにjava.lang.String#matchies()では正規表現を引数に持っています。詳細は[リンク先のJavaDoc](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/String.html#matches-java.lang.String-)を見てみてください。

一応ですが、「正しい答え」というものはありません。想定通りに動けばそれが正解です。人生の中で「正解」がないのと同じです。
ちなみに自分の作成したものは次のように動きました。

作成したコードはGitにあります。
ちなみに、テストクラスも作成しました。入力した文字を判定する処理のテストです。このクラスの名前にはお尻の部分に「Test」をつけて「Lv2__1_CalculateTest」とするのが規約に則ったやり方なのですが、つけ忘れてしまいました。
このまま修正しないでいると、後々に何かしらのミスをやります。。。


まとめ

ここで、実装のサンプルとかそんなものを記載しようかと思ったのですが、Gitにあげるまでにしておきます。
感覚としてはパズルとか、なぞなぞを解くような感じで追加で設計した部分を実装して見てください。

余談

テストを作成〜テストの実行までを動画にしました。

でわでわ。。。

<<< 前回 次回 >>>

  1. Java Basic Level 1 Hello Java
  2. Java Basic Level2 Arithmetic Calculate
  3. Java Basic Level3 About String class
  4. Java Basic Level 4Boolean
  5. Java Basic Level 5If Statement
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 Traning of If statement
  8. Java Basic Level8 How to use for statement
  9. Java Basic Level 8.5 Array
  10. Java Basic Level 9Training of for statement
  11. Java Basic Level 10 While statement
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1
  17. Java Basic JUnit 〜テストスイートの作り方〜

Java Mid Basic 〜Lv2_Javaの基本(コードの書き方)ゲームループ付き〜

イントロダクション

前回は、とりあえず入力して画面に表示するものを作成しました。こんな感じです。

動画は、作成中にデバッックしたものです。ちなみにバグもあります。
とりあえずは「動いた!」という感動を味わっていただきたく思い、中途半端ですが、アプリとして動くものを作成しました。
コードはGitにアップしています。

最終的にはコンソールゲームを作ります。
<Eclipse上のコンソール(全画面状態です)>

<Eclipseの全画面でない場合>

<コンソール(=標準出力)にPHPの実行結果を表示>

AP概要Lv2

標準入力を受け付けて、以下のような動きをします。

  1. 入力された文字が「hello」の時はコンソールに「Hello World!」と表示する。
  2. そのほかの文字を入力したら「想定外の入力です」を表示する。

四則計算をする

今回のメインになる実装を行います。前回の記事で問題を出しました。ちょっと難しい問題でした。上の動画はデバック中の動画になります。バグも残っています(笑)。

まずは書いたコードの理解

前回作成したコードをもう一度眺めてみます。

public class Lv2HelloWorld {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        while(true) {
            System.out.print("入力してください: ");
            String inStr = input.nextLine();
            if ("hello".equals(inStr)) {
                System.out.println("Hello World!");
            } else {
                System.out.println("想定外の入力です");
                break;
            }
            System.out.println("Next command ... ");
        }
        System.out.print("AP is fiinished. Bye!");
    }
}

頭(行の先頭)からコードの意味を記載していきます。

クラスの定義

上のコードで行くと、下の部分がクラス定義になります。

public クラス名{ .... }

このクラス名はなんでも良いのですが、下のルール(大雑把な規約)にしましょう。ちなみにCheckStyleというEclipseのプラグイン(標準装備)を使用すると簡単に規約違反が見つけられるので便利です。参考サイト

  • メタ文字:%/\&'*)など、これらはEclipseなどのIDE(開発ツール)を使用するとエラーが出るので安心です。
  • Javaのクラスはアッパーキャメルケース("AppaKyameru"のように書く)を使用します。
  • Javaのメソッドはキャメルケース("appaKyameru"のように書く)を使用します。

とりあえずはこんなところを気をつけましょう。

メイン・メソッドの定義

まずは動かしたいので「メインメソッド」を作成します。メインメソッドは以下のような特徴があります。

  1. メソッドの定義は1つだけ、ほかの書き方はない。※引数の名前は変更しても大丈夫
  2. 必ずこのメソッドが動く
  3. 引数は「プログラム引数」になる

プログラム引数

プログラム引数はEclipseで使用する場合は下のように値を渡してあげます。つまりString[] argsの部分が引数であり、下のように設定してアプリを起動すると変数「args」に"プログラム引数1"のように値を渡せます。
注意として、プログラム引数は「String」型のデータになります。

ちなみに「データ型」に関しては後々に触れますが、現在使用しているデータ型は「int」「String」があります。

int型

調べてみると「???〜???までの整数」などのように記載されてますが、早い話が、範囲指定はあるけど(正負の)整数です。Stringなどの「オブジェクト型」とか「参照型」など(同義です)と違い、直接の値(メモリの領域)を保持します。

String型

これはjava.lang.Stringというクラスの型になります。intと違い「クラス」なので「null」が存在します。よく「参照型」とか「オブジェクト型」などと呼ばれます。早い話が「NULLが存在する型」なんだな!と理解してくれればOK!今後深く理解していきます。int型などのように直接、値を持つ変数と違いオブジェクトへの参照(ポインタ)を変数に持ちます。だからNULLがあるのです。

次は実装

すでに書いたコードに追記・編集していきます。前回作成したメインメソッド部分では「Hello World」と「想定外 ....」を出力するだけだったので、この部分を拡張します。
元のコード

public static void main(String[] args) {
    System.out.println("プログラム引数のサイズ:" + args.length);
    for (int i = 0; i < args.length; i++) {
        System.out.println("プログラム引数:" + args[i]);
    }
    Scanner input = new Scanner(System.in);

    while(true) {
        System.out.print("入力してください: ");
        String inStr = input.nextLine();
        if ("hello".equals(inStr)) {
            System.out.println("Hello World!");
        } else {
            System.out.println("想定外の入力です");
            break;
        }
        System.out.println("Next command ... ");
    }
    System.out.print("AP is fiinished. Bye!");
}

編集後のコード

public static void main(String[] args) {
    // 今回は作成したこのクラスを使用します。
    Lv2_1_Calculatie myClass = new Lv2_1_Calculatie();

    Scanner input = new Scanner(System.in);

    while(true) {
        System.out.print("入力してください: ");
        String inStr = input.nextLine();
        if ("hello".equals(inStr)) {
            System.out.println("Hello World!");
        } else if (inStr.matches("[0-9].*")) {
            int answer = myClass.calculate(inStr);
            System.out.println("答えは:" + answer + "です。");
        } else {
            System.out.println("想定外の入力です");
            break;
        }
        System.out.println("Next command ... ");
    }
    System.out.print("AP is fiinished. Bye!");
}

具体的に下の部分が変わりました。

Lv2_1_Calculatie myClass = new Lv2_1_Calculatie();
} else if (inStr.matches("[0-9].*")) {
    int answer = myClass.calculate(inStr);
    System.out.println("答えは:" + answer + "です。");

new Lv2_1_Calculatie()の部分は作成したクラスのインスタンスを取得しています。
インスタンス化すると「インスタンスメソッド」が使えるようになります。

インスタンスメソッドとスタティックメソッド

インスタンスメソッド:A a = new A();のように「new」してから使用する
スタティックメソッド:A.staticMethod()のようにクラス名.メソッド名で呼ぶことができる
上のような違いがあります。

まとめ

クラスとメソッドの書き方、メソッドの種類について触れました。結局計算する部分には触れませんでしたので次回触れようと思います。
でわでわ。。。

<<<前回 次回>>>

  1. Java Basic Level 1 Hello Java
  2. Java Basic Level2 Arithmetic Calculate
  3. Java Basic Level3 About String class
  4. Java Basic Level 4Boolean
  5. Java Basic Level 5If Statement
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 Traning of If statement
  8. Java Basic Level8 How to use for statement
  9. Java Basic Level 8.5 Array
  10. Java Basic Level 9Training of for statement
  11. Java Basic Level 10 While statement
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1
  17. Java Basic JUnit 〜テストスイートの作り方〜

Java Mid Basic 〜Lv1Javaの基本を理解する(ゲームループ付き)〜

イントロダクション

Javaの基本を改めてやろうと思います。
今までの「Java Basic」シリーズは基本的なことをやった後に「基本を使用して何かをする」というのが目的だったのですが、基本の練習をしていなかったことに気がつき。。。現在に至るという次第です。

ハローワールド

初めのプログラムとしてどの言語でも使用するプログラムです。このプログラムは応用範囲が広くいろんな場所で使用できます。
基本にするページは下のリンクになります。
Java Hello World はじめのプログラム 〜 Step1-1〜ここの記事では、以下のようなことを記載しています。

  1. Javaは、メインメソッドが動く
  2. クラスやメソッドの書き方
  3. 練習問題

今回やること

Hello Worldの応用として、標準入力を使用したシンプルアプリケーションを作成してみようと思います。
この処理は、今後実装するSocket通信で使用することもできます。

標準入力の実装

標準入力に関しては、JavaAPI(JDK)ですでに用意されています。具体的には「System.in」です。言葉にすると「Systemクラスのフィールド変数『in』」のことです。これを使用してユーザーの入力を受け取るには下のようなコードを使用します。

Scanner scan = new Scanner(System.in);
String input = scan.readLine();

このコードは、入力した文字(Enterキーが押下されるまで)を取得します。文字列型の変数「input」に入力した文字列を受け取ります。

問題のポイントは受け取った文字列を使用して標準出力へ指定の文字列を表示するところです。

問題

標準入力を受けて、受けた文字列により以下の文言をコンソールに表示するプログラムを作成してください。
[ヒント]Gitにアップしてあるコードを参考にしてみてください。

  1. IN: "hello" => OUT: "Hello World!"
  2. IN: "タイガー" => OUT: "マイコンジャー!炊きたて!"
  3. IN: "1 + 1" => OUT: "2"
    ただし、"2 * 4"などのように計算式の場合は計算した結果を表示する

イメージ

サンプルコード

JavaのCodeはGitにアップしてあります。

public class Lv2HelloWorld {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        while(true) {
            System.out.print("入力してください: ");
            String inStr = input.nextLine();
            if ("hello".equals(inStr)) {
            System.out.println("Hello World!");
            } else {
                System.out.println("想定外の入力です");
                break;
            }
            System.out.println("Next command ... ");
        }
        System.out.print("AP is fiinished. Bye!");
    }
}

これで、入力→コンソール表示の簡単なゲームが作成できると思います。
是非、遊んでみてください。

## ポイント
1. 標準入力を受けて、受けた文字列を条件分岐させて表示内容をハンドルするところです。
2. 無限ループの中にループを脱出する処理を入れるところです。これを入れないと処理が終わりません。

### 条件分岐

### 無限ループ
無限ループのサンプルコードです。
```java
while(true) {
// 何かしらの処理
}
```
無限ループするならこのコードがシンプルで、自分は気にっています。

でわでわ。。。
次回>>>

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜