Java Basic ミニゲーム作成 〜Step3_2〜

イントロダクション

前回は、説明が不十分な感じでした。
とりあえずで"bye"と入力すると終了するコンソールアプリを作成しました。
今回は、タイトル表示までやりました。
ただし、Mainクラス単体では動きません。。。

使用するクラス

必要なクラスは以下になります。

RpgMain
ViewStatus
TitleView

RPGMainクラス

RPGMainでゲームの処理をstaticで作成しています。つまりは、メインメソッドから直接呼び出せる形で実装しています。
※RpgMain#view()メソッドは使っておりません。今後の実装を考えて作っておりますので今後修正する可能性が大きいです。
※2024/01/11現在ではXMLを読み込む形になりました

<実行動画>

/** 
 * ゲームを起動する </br>
 * 標準入力の受付、「bye」コマンドでAPを終了する</br>
 * 
 * @param args プログラム引数
 */
public static void main(String[] args) {
    // 初期化処理
    init();
    try {
        // ゲーム起動(GameLoop開始)
        gameLoop();
    } catch(IOException ie) {
        ie.printStackTrace();
        System.exit(-1);
    }
    // リソースの解放
    terminated();
}

作成したもの

処理の概要

メインメソッドでは、大まかに下のような処理をしています。

  1. 初期化処理
  2. ゲームループ
  3. 終了処理

ここのポイントは、ゲームループです。

ゲームループは、一定の処理を行い、それに対応して様々な画面への反映を行います。下のような処理を行います

  1. 入力を受ける
  2. データの更新を行う
  3. 画面の更新を行う

処理内容:メインメソッド

  1. 初期化 #init
    • RpgMainクラスを生成(new)して
    • メンバメソッドinitialize()で初期画面の標準入力を受け付ける
    • ファイルの読み込み&出力 ※ラムダ式を使用してみました
    • 初めの画面管理オブジェクト生成
/**
 * このゲームでは初期化は必ず1回なのでstaticをつける</br>
 * static -> 静的メソッド=> クラス内にあるがJVMから直で参照される
 * ※JVM => Java Virtual Machine
 */
private static void init() {
    // mainメソッドと同様にクラスをnewする必要あり
    game = new RpgMain();
}
  1. ゲームループ #gameLoop
    • 無限ループ開始
    • コマンド実行処理(Mainクラス) ※画面管理オブジェクトのexecuteを実行
    • 更新後の画面を表示
/**
 * この処理もinit()と同様に必ず1回なのでstaticをつける</br>
 */
private static void gameLoop() throws IOException{
    /*
     *  <ゲームループ> 
     *  1.入力
     *  2.データ更新、
     *  3.レンダリング(今回はコマンドなので文字出力)
     *  4.「bye」コマンドでゲームを終了する
     */
    while(true) {
        // 1. 入力を受け取る
        String command = game.listenInput();
        // command変数がnullになる可能性があるため定数.equals()の形にする
        if(TERMINATE_GAME.equals(command)) {
            break;
        }
        // 2-1.処理を実行する(タイトル、その他初期表示する
        status = game.execute(command);
    }
}
  1. 終了処理 #terminated
    • リソース(クラス)のメモリ解放
/**
 * ゲームのリソースを解放する
 */
public static void terminated() {
    // クラスの解放を行う
    game = null;
    System.out.println("This game terminated!, See you next time!!");
}

「static」をつけているのは、Mainメソッドから
直接呼ぶ様にしたかったからです。→メインメソッドとクラスのメンバメソッドを分けると見やすいと思ったため。

ViewStatusクラス

このクラスは、抽象クラスで、今後作成していく表示する画面を実行するためのクラスです。大まかに今回の実装のかなめになるクラスです。
ViewCommandはインターフェースですが、インナークラスとして実装しています。
※正しくは、インターフェース・クラス

このクラスの使い方としては、各画面クラス(TitleViewクラスなど)で以下のメソッドをオーバーライドしてやれば、コマンドに対応した処理を実行する
というような実装を行いました。

/** 画面の表示処理 */
public abstract void views();
/** 使用するコマンド */
public abstract Optional<Map<String, ViewCommand>> createCommands();
/** ViewStatusをセットする */
public abstract void setViewStatus(ViewStatus status);
/**
 * 画面のステータスクラスを示す。<BR>
 * コマンドの実行は内部インターフェースViewCommand<BR>
 * の実装クラスが行う<BR>
 * 【使い方】
 * 1. このクラスを継承して全ての抽象メソッドを実装します。
 * 2. コンストラクタでcreateViewStr()を呼び出して画面(文字列)を
 *    デザインしたファイルを指定してください読み込んで表示します。
 * 
 * @author takunoji
 */
public abstract class ViewStatus {
    /** 自クラスを保持する */
    protected ViewStatus status;
    /** コマンド管理 */
    protected Map<String, ViewCommand> commands;
    /** 表示する画面(文字列) */
    protected List<String> viewStrList; 

    /**
     * インナークラスのインターフェース
     * @author takunoji
     */
    public interface ViewCommand {
        /** コマンドの実行
         * Nullが返却されるときは画面の遷移なし 
         */
        public abstract ViewStatus execute();
    }

    /**
     * コンストラクタ<BR>
     * 使用するコマンドをMapに設定する
     */
    public ViewStatus() {
        Optional<Map<String, ViewCommand>> optCommands = createCommands();
        // 取得した結果がNullの場合はからのMapを返す
        commands =  optCommands.isPresent() ? optCommands.get() : new HashMap<String, ViewCommand>();
    }

    /**
     * コマンド実行処理<BR>
     * RpgMainクラスで標準入力を受けてコマンドマップに<BR>
     * 登録されているViewCommandのexecuteを実行する<BR>
     * Mapに登録されていない時は何も実行しない
     * @param input
     * @return
     */
    public ViewStatus execute(String input) {
        Optional<ViewCommand> command = Optional.ofNullable(commands.get(input));
        // commandがからの場合は何もしない
        command.ifPresent(cmd -> setViewStatus(cmd.execute()));
        return this;
    }

    /**
     * ファイルを読み込み画面を描画する(文字列)
     * @param filePath
     */
    protected void createViewStr(String filePath) {
        Path path = Paths.get(filePath);
        List<String> lines = null;
        try {
            lines = Files.readAllLines(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        lines.stream().forEach(System.out::println);
        // viewの文字列を保存します
        this.setViewStr(lines);
    }

    /** 作成、ファイルから読み込んだView文字を保存する */
    public void setViewStr(List<String> viewStrList) {
        this.viewStrList = viewStrList;
    }
    /** 作成、ファイルから読み込んだView文字を取得する */
    public List<String> getViewStr() {
        return this.viewStrList;
    }

    /** 画面の表示処理 */
    public abstract void views();
    /** 使用するコマンド */
    public abstract Optional<Map<String, ViewCommand>> createCommands();
    /** ViewStatusをセットする */
    public abstract void setViewStatus(ViewStatus status);
}

TitleViewクラスについて

そして、初めの画面管理オブジェクトのTitleViewは「ViewStatus」という抽象クラスを実装しています。
抽象クラスについてはのちに説明いたしますが、インターフェースとクラスの中間にいるクラスです。

具体的に、抽象メソッドと実装するメソッド両方を持っております。
インターフェースと違いimplemensではなく「extends」(継承)する必要があります。
さらにちょっと厄介なインナークラスにインターフェースを作成しています。

ViewStatus以外で、使用することのないインターフェースなのでそうしたのですが、普通は外部に作成します。
クラスが増えない様に、インナークラスにしたのですがやっぱり微妙でした、なんかのタイミングで修正しようと思います。

インポートするときはxxxxViewStatus.ViewCommandの様にやります。

まとめ

以下のクラスを使用しました。それぞれの役目を割り当てています。

  • RpgMain: ゲームを動かす。メインメソッドを起動するためのクラス。
  • ViewStatus: 抽象クラス、このクラスを継承したクラスはすべて、画面状態を示すクラスとして使用する。
  • TitleView: タイトルを表示するステータス(状態)を表現するクラス。

ここまでで、とりあえずは実装をどんどん拡張する準備が整った形です。
具体的には、「ViewStaus」クラスを継承して新しいクラスを作成するということです。

現状では、TitleViewクラスのみですが、これを増やしていけば一つのアプリが作れるかもしれません。

とりあえず、今回はここまでにします。でわでわ。。。

次回は、ミニゲーム作成-〜コンソールゲーム〜/

です。

関連ページ

前回

http://zenryokuservice.com/wp/2018/05/20/java-basic-ミニゲーム作成-〜コンソールゲーム〜/

インターフェースについて

http://zenryokuservice.com/wp/2018/06/01/java-basic-インターフェース・抽象クラスの作り方/

ページ一覧

http://zenryokuservice.com/wp/2018/09/29/mapping-of-java-bassic~java-basicの記事一覧~/

Java Basic ミニゲーム作成 〜Step3_1〜

イントロダクション

はじめにコンソール画面を使用してミニゲームを作成しようと思っています。
標準入力(コンソール画面に入力する)を使用して行いますので、参考までに標準入力のサンプルを載せておきます。

標準入力の動き

最終的に作成したもの

ミニゲームを作る

  • ミニゲームの作成を行います。
    処理の概要としては、以下の通りです。( version0.1)
=====補足==========
<基本設計レベル>
[詳細設計レベル]
==================

<初期処理>
画面状態管理Obj
リソースの読み込み
[テキストで表示する絵を読み込み変数に保存]→テキストファイル

[新規で追加するファイルも読み込める様に工夫する]

<選択→決定処理>
ゲームタイトル画面の「スタート」「コンテニュー」の選択をする

以下の様に表示する

START:S
CONTINUE: C
<イントロダクションの表示処理> イントロダクションのテキストファイルを読み込み ストーリーの序章を表示して、ゲームを開始できる様な文章を表示する

この仕様で実装します。

  1. 画面状態管理クラスの作成

    • シンプルにMap型のフィールド変数を作成します。
  2. リソースの読み込み、単純にテキストファイルの読み込みです。

※今後はプロパティファイルなど読み込む予定です。(XMLもやるかも?)リメイクの方(Github)で使用しています。

※未実装です

  1. これもテキストファイルを読み込みゲームの序章を表示します。

今回は、ここまでを実装します。

土台にするのは以前の実装です。
クラス名はブログの都合上変えてあります。
そして「画面状態」は今回初登場の「Map」インターフェースを使用して管理します。

<<元にするソースについて>>

ゲームの基本的な処理フロー

初期化→ゲームループ→終了

上記のメソッドを実装してあります。

まとめると

  1. ゲームの起動準備「init();」
  2. 入力→画面の更新をループする「gameLoop()」
  3. ゲームの終了「terminated()」

上記の3つの処理の中で、ゲームを進行させていくと言うことです。が実装してみないとイメージがわかないと思います。※イメージが湧く人は頭のいい人です。筆者は試行錯誤済みです。

そして、「3つの処理」というのは「」の中に書いてある各メソッドのことを指します。

  • init()
  • gameLoop()
  • terminated()

それぞれの処理は以下のようになります。
<init: 初期処理>

/**
* このゲームでは初期化は必ず1回なのでstaticをつける</br>
* static -> 静的メソッド=> クラス内にあるがJVMから直で参照される
* ※JVM => Java Virtual Machine
*/
private static void init() {
    // mainメソッドと同様にクラスをnewする必要あり
    game = new RpgMain();
}

ここで実行しているのはコンストラクタになります。

/**
* ぶっちゃけてここで初期化(init)処理をやっても良い</br>
* 最終的にプログラムの設計者の判断に委ねられる</br>
*/
public RpgMain() {
    // メンバメソッドなのでコンストラクタで呼び出す
    initialize();
}

そして、inittialize()メソッドを実行しています。フィールド変数にTitleViewクラスを代入(セット)しています、

/**
* 入力、出力のためのオブジェクトを生成</br>
* RpgMainクラスが存在しないならば使用できない様にするので</br>
* このメソッドはメンバメソッドにしてある</br>
*/
public void initialize() {
    // 入力受付クラス
    read = new BufferedReader(new InputStreamReader(System.in));
    // *** titleの表示 *** //
    // ViewStats生成
    status = new TitleView();
}

<gameLoop: 初期処理>

/**
 * この処理もinit()と同様に必ず1回なのでstaticをつける</br>
 */
private static void gameLoop() throws IOException{

    /*
    *  <ゲームループ> 
    *  1.入力
    *  2.データ更新、
    *  3.レンダリング(今回はコマンドなので文字出力)
    *  4.「bye」コマンドでゲームを終了する
    */
    while(true) {
    // 1. 入力を受け取る
    String command = game.listenInput();
    // command変数がnullになる可能性があるため定数.equals()の形にする
        if(TERMINATE_GAME.equals(command)) {
            break;
        }
        // 2-1.処理を実行する(タイトル、その他初期表示する
        status = game.execute(command);
    }
}

ここでは、「String command = game.listenInput();」で標準入力を受け取っています。
そして受けた文字列から実行するコマンドを実行して処理後にTitleViewクラスを受け取っています。

<terminated: 終了処理>

/**
* ゲームのリソースを解放する
*/
public static void terminated() {
    // クラスの解放を行う
    game = null;
    System.out.println("This game terminated!, See you next time!!");
}

サンプルコードは一番上の「ミニゲーム」の部分にリンクしています。

コンソールゲームで初めのタイトルが表示される様なものです。初めはこれからストーリーをつけて。。。と考えていたのですが、ストーリーができず。。。保留状態です。。。※作成しました。作成したものは上部にYOutube動画があります。

実装したコード

この記事の上部にあるリンク先にはGithubで見ることができます。関連クラスも同様にアップロードしてあります。

/**
 * コマンドラインRPGのメインクラス</br>
 * <ul>
 * 機能リスト
 * <li>1.必要なリソースを読み込む #init</li>
 * <li>2.ゲーム起動(コマンド入力) #gameLoop</li>
 * <li>3.リソースの解放</li>
 * <li>ゲーム終了(このメインメソッドの終了)</li>
 * </ul>
 * @author takunoji
 */
public class RpgMain {
    /** フィールド変数で自信を管理 */
    private static RpgMain game;
    /** 定数: AP終了コマンド */
    public static final String TERMINATE_GAME = "bye";
    /** 入力を受付るオブジェクト */
    private BufferedReader read;
    /** 画面状態管理オブジェクト */
    private static ViewStatus status;

    //////////////////////////////////////
    // staticメソッドの定義
    //////////////////////////////////////
    /** 
     * ゲームを起動する </br>
     * 標準入力の受付、「bye」コマンドでAPを終了する</br>
     * 
     * @param args プログラム引数
     */
    public static void main(String[] args) {
        // 初期化処理
        init();
        try {
            // ゲーム起動(GameLoop開始)
            gameLoop();
        } catch(IOException ie) {
            ie.printStackTrace();
            System.exit(-1);
        }
        // リソースの解放
        terminated();
    }

    /**
     * このゲームでは初期化は必ず1回なのでstaticをつける</br>
     * static -> 静的メソッド=> クラス内にあるがJVMから直で参照される
     * ※JVM => Java Virtual Machine
     */
    private static void init() {
        // mainメソッドと同様にクラスをnewする必要あり
        game = new RpgMain();
    }

    /**
     * この処理もinit()と同様に必ず1回なのでstaticをつける</br>
     */
    private static void gameLoop() throws IOException{

        /*
         *  <ゲームループ> 
         *  1.入力
         *  2.データ更新、
         *  3.レンダリング(今回はコマンドなので文字出力)
         *  4.「bye」コマンドでゲームを終了する
         */
        while(true) {
            // 1. 入力を受け取る
            String command = game.listenInput();
            // command変数がnullになる可能性があるため定数.equals()の形にする
            if(TERMINATE_GAME.equals(command)) {
                break;
            }
            // 2-1.処理を実行する(タイトル、その他初期表示する
            status = game.execute(command);
        }
    }

    /**
     * ゲームのリソースを解放する
     */
    public static void terminated() {
        // クラスの解放を行う
        game = null;
        System.out.println("This game terminated!, See you next time!!");
    }

    //////////////////////////////////////
    // コンストラクタ、メンバメソッドの定義
    //////////////////////////////////////
    /**
     * ぶっちゃけてここで初期化(init)処理をやっても良い</br>
     * 最終的にプログラムの設計者の判断に委ねられる</br>
     */
    public RpgMain() {
        // メンバメソッドなのでコンストラクタで呼び出す
        initialize();
    }

    /**
     * 入力、出力のためのオブジェクトを生成</br>
     * RpgMainクラスが存在しないならば使用できない様にするので</br>
     * このメソッドはメンバメソッドにしてある</br>
     */
    public void initialize() {
        // 入力受付クラス
        read = new BufferedReader(new InputStreamReader(System.in));
        // *** titleの表示 *** //
        // ViewStats生成
        status = new TitleView();
    }

    /**
     * 入力受付を開始、入力結果を取得する</br>
     * @return 入力文字列(コマンド)
     * @throws IOException
     */
    private String listenInput() throws IOException {
        return read.readLine();
    }

    /**
     * コマンドの実行を行う<BR>
     * 1.
     * @param input
     * @return
     */
    private ViewStatus execute(String input) {
        status = status.execute(input);
        return status;
    }

    private void view() {
        if(status != null) {
            status.views();
        }
    }
}

[rakuten ids="book:19065927"]

関連ページ一覧

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 Basic インターフェース 〜Step2_3 〜

イントロダクション

インターフェース・クラスや、
ポリモーフィズムについて学習していきます。
ポリモーフィズムは、日本語で「多様性」と言う意味らしいです。
インターフェースクラスの前に通常のクラスについて理解したい場合は、こちらの記事を参照ください。

ポリモーフィズムの使用例

よく聞く「デザインパターン」と言うのはこのポリモーフィズムを応用した設計手法のことです。

<インターフェースクラスの使い方サンプル>

余談

JavaAPIの中にはすでに実装されています、
Listインターフェース・クラスにある。iterate()はイテレートパターンと言うデザインパターンの実装になります。

インターフェース・クラス

インターフェース・クラスに関してはListインターフェースがこれにあたります。まずはこのインターフェースクラスを見てみましょう。

List<String> list = new ArrayList<String>();

List<String> list = new LinkedList<String>();

上のように、別クラスを同じ型(クラス)変数として使用することができます。

これがまずは、基本的な考え方になります。これは、ArrayListがListインターフェイスをimplementsしているのでこのような使い方が出来ます。JavaDocを見ると他にも実装(implements)しているクラスを確認できます。

インターフェースクラスを作成すると、このインターフェースクラスを一つのグループとして使用することができます。

ListインターフェースクラスのJavaDocを見てみると「既知の実装クラス」の部分にあるクラスが実装(implements)しているクラスです。つまり1つのグループとして扱うことができるというわけです。

自作のインターフェースを使う

自作のインターフェースを使ってみます。
概要としては以下のようなクラスを用意します。

  1. TestIF(インターフェース)
  2. TestCls1(インターフェースの実装クラス)
  3. TestCls2(インターフェースの実装クラス)

なお、各実装は以下のように定義します。作成したメソッドには処理の実体がありません。このようなメソッドを抽象メソッドと呼び、「abstract」をつけるのですが、インターフェイスクラスではつけなくても良いことになってます。その代わり抽象クラスを作った時は「abstract」を付ける必要があります。
<TestIF>

public interface TestIF {
    // 抽象メソッドを定義、処理の中身はなし
    public abstract void hello();
    // 上と同じように抽象メソッドの定義
    public void execute();
}

インターフェイスのメソッドをオーバライドして処理の実体を作成します。
<TestCls1>

public class TestCls1 implements TestIF {
    @Override
    public void hello() {
        System.out.println("Hello World");
    }
    @Override
    public void execute() {
        int ans = 1 + 1;
        System.out.println("足し算の結果: " + ans);
    }
}

<TestCls2>

public class TestCls2 implements TestIF {
    @Override
    public void hello() {
        System.out.println("Good morning World");
    }
    @Override
    public void execute() {
        int ans = 5 * 2;
        System.out.println("掛け算の結果: " + ans);
    }
}

これを、変数testに格納して起動してみます。コードは下のようなものです。

public static void main(String[] args) {
    // インターフェースクラスを宣言する
    TestIF test1 = new TestCls1();
    test1.hello();
    TestIF test2 = new TestCls2();
    test2.hello();
}

実行結果

それぞれ、「Hello World」と「Godd morning World」が表示されます。
このように、インターフェースクラスを使用して、一つのクラス型(データ型)でいろんな処理を実装することを「多様性」という意味の
ポリモーフィズムという言葉が使用されています。しかし、エンジニア同士の会話の中で認識を合わせるための言葉なので
自分なりのちゃんとした理解があれば、認識を合わせることができると思います。

「単語」にとらわれていると「スタティックおじさん」事件のように、カオス化してしまうので注意しましょう。

Gitにアップしたソースについて

作成したクラスなどは、Githubにアップしてあるのでそちらを参照ください。ルートになるフォルダはこちらになります。
作成したものjp.zenryoku.sample.basic.lv2パッケージになります。※上記のものと違っているかもしれません。

インターフェースの書き方

public interface インターフェース名 {
   /** 抽象メソッドの定義 */
   // implementsするクラスで処理内容を記述
   public abstract void execute();
  // 上のメソッドと同じ(メソッド名は違う)
   public void setName();
}

クラスへの実装(implements)方法

public class クラス名 implements インターフェース {
   // クラスの記述
   // 上記の抽象メソッドを実装する
  @Orverride
   public 抽象メソッド() {
      //処理
  }
}

インターフェースを使用した。
サンプルコードには上記の実装方法を使用しています。
実際の使用の仕方はサンプルを見てください。

インターフェースを実装したクラスは、そのインターフェース型の
変数として使用することができます。
つまり、同じ名前のメソッドを呼び出した時に違う処理を実行することがでいます。
下の「action()」の実行結果が以下になります。
listにはPlayer型のクラスが設定されています。
処理詳細は、サンプルコードをご覧ください。

作成したインターフェースクラスを今後作成するクラスに実装(implements)することで、下のようなコードでどのクラスの「execute()」メソッドも実行することができます。

public void test() {
   // SomeClsにTestIFを実装(implements)した場合
   TestIF ttt = new SomeCls();
   ttt.execute();
   ttt.hello();
   // OtherClsにTestIFを実装(implements)した場合
   TestIF tt1 = new OtherCls();
   tt1.execute();
   tt1.hello();
}

CommandIFを使ったポリモーフィズム

CommandIFというインターフェースクラスを作成し、これを実装(implements)したクラスを、入力した文字列によって呼び出す形のプログラムを実装しました。参考にどうぞ

次回、これだけではわかりづらいかもしれないので
他もパターンも記載いたします。

Java Basic API Listインターフェイスの使い方 〜Step2_2〜

Listの使い方

よく世間では「リスト」と言う言葉を使用します。「〜のリスト作っておいて!」などといったりします。しかし、左のリストとここでいうリストは別物で、JavaAPIにある「Listインターフェースクラス」のことです。

まずは実装してみたので、こんな感じかな?と言うのをみてもらうのが早いと思います。

このリストはJavaAPIに存在していて完全クラス名はjava.util.Listです、そして、詳細な説明があるJavaDocはこちらのリンク先にあります。

クラスと言いましたが、これは「インターフェース・クラス」実体のないクラスです。これは実体のあるクラスを格納できる変数だと思ってもらえれば、ある程度はわかりやすいと思います。そして、実体とは処理の中身のことをいいます。

更にういなら、実体のない時はメソッドの型のみで、実体のある時は中かっこがついてます。

Listインターフェース・クラス

List<String> list1 = new ArrayList<String>();

他にも下のような実装もできます。

List<String> list1 = new LinkedList<String>();

JavaDocにある既知の全ての実装クラスと言う部分に記載のあるクラスは同じように扱うことができます。

Listの扱い方

Listインターフェースクラスの実装に関して、既知の実装クラスでよく使用されるのが「ArrayList」クラスです。このクラスは、可変長配列の実装です。なので配列の長さを気にせずに、配列にデータを追加、削除することができます。
つまり、昔の配列は配列の長さを調節する処理が必要だったわけです。先人たちの苦労を無駄にしないようにクラスという形で残っていると思うと少し感慨深いですね。

Listインターフェースクラスのサンプル実装


public void test03() {
    // OK牧場(笑)
    List list = new ArrayList();
    list.add("test01");
    list.add("test02");
    list.add("test03");
    List list1 = new LinkedList();
    list1.add("public1");
    list1.add("public2");
    list1.add("public3");

    this.systemOut(list);
    this.systemOut(list1);
}
private void systemOut(List list) {
    // FOR文
    for(int i = 0; i < list.size(); i++) {
        System.out.println("リスト(" + i + "): " + list.get(i));
    }
    // 拡張FOR文
    for(String value : list) {
        System.out.println("リスト: " + value);
    }
}   ```
上記のように、扱い方は同じですが、微妙に違いがあります。

* ArrayList: サイズ変更可能な配列の実装です。※可変長配列
* LinkedList: 両端で要素の挿入および削除をサポートする線形コレクション

【配列の扱いあれこれ】

配列を使用して様々なデータを検証、編集など 色々な処理を行いますが何かと不便なこともあります。 String[] args = new String[5]; の様に初期化した場合→test01();

サンプルソースのダウンロードができます。

この場合は、配列の数が決まるので困る時があります。 例:標準入力を受けるとき byte[] b = new byte[5]; System.in.read(b);

上記の場合は、5文字までを受け取ることができます。 少なかったり多かったりすると上手くないのです。。。 なので前回はBufferedReaderを使用してそこを解消しました。

そこで、初めの配列(byte[] b)をString[], int[]などに変更した場合 かつ標準入力出ない場合はどうしたら良いでしょうか?

【Listクラスを使用する】

ここで、Listが出てきます。完全修飾名(完全クラス名)は 「java.util.List」クラスです。正しくはインターフェースクラスになります。 このインターフェースは以下のクラスに実装されています。 他にもあるけれど、使用頻度の高いものを記載します。

java.util.ArrayListクラス(完全修飾名) ・java.util.LinckedListクラス(完全修飾名) ・java.util.Vectorクラス(完全修飾名)

これらのクラスにはclass名の後に「implements java.util.List」 が記載されています。

これが「実装する」という意味です。 // インターフェースの定義 public interface List { ....}の様に記載します。 実際のjava.util.Listインターフェースの内容は Eclipseを使用しているならListの文字の上で「F3」を押下すると ソースを見ることができます。 実際のインターフェース定義は以下になります。

public interface List<E> extends Collection<E> {
    // Query Operations

インターフェース定義でも「extends」とありますが
とりあえず置いておきます。

ではインターフェースって何?となると思います。
インターフェースはクラスに実装(implements)することにより
インターフェースで複数のクラスを一つの変数で扱えます。

例として、ListはArrayListとLickedListをListの変数で使用できます。
List<String> list = new ArrayList<String>();
// OK牧場(笑)
List<String> list1 = new LinkedList<String>();
の様に別のクラスでも同じ変数で使用することができます。
【追伸】
List<変数の型>の「変数の型」の部分は、ジェネリクスと言います。
コードが長くなってくるとこのリストの中身はなんだった?
とわからなくなってしまいます。それを解消したのがこの
「ジェネリクス」です。
その他Map, Set, Vectorなどで使用します。

でわでわ。。。

Java Basic try catch文 〜Step1_3_3〜

イントロダクション

忘れ去られがちですが、エラーハンドル(エラー時に何をするかコントロールする)を行うのには、この文法が基本となります。

実装して動かしてみました。余計な音が入っています。

Exceptionの種類によりコントロールすことができます。コントロールと言ってもExceptionの種類によって処理をかえるというものです。
ちなみにしたの場合は、どんなエラーでもキャッチします。

具体的には、下のように「catch(Exception e)」と書くことですべての例外をキャッチします。


try {
    // 例外が予想される処理
    // throws文のあるメソッド呼び出し
} catch(Exception e) {
    // 例外の内容を表示
    e.printStackTrace();
}

参照するファイルが見つからないときの例外をキャッチしたいとき+すべての例外をキャッチ。

try {
    // 例外が予想される処理
    // throws文のあるメソッド呼び出し
} catch(FileNotFoundException e) {
    // 例外の内容を表示
    e.printStackTrace();
} catch(Exception ex) {
    // 例外の内容を表示
    e.printStackTrace();
}

入出力関連のエラー(例外)をキャッチ+すべての例外をキャッチ。

try {
    // 例外が予想される処理
    // throws文のあるメソッド呼び出し
} catch(IOException e) {
    // 例外の内容を表示
    e.printStackTrace();
} catch(Exception ex) {
    // 例外の内容を表示
    e.printStackTrace();
}

他にもあるのでそれに合わせたExceptionをキャッチしてやれば、どんな例外にも対応が可能!

ちなみにIF文と同じで、Exceptionをキャッチする行を上に持ってくると、下のキャッチ文に届きません。。。

try catch文

基本的な使い方としては、入出力や様々なところでエラーハンドルを行うために使用します。他にも「throw new Exception("メッセージ")」のように独自のメッセージを例外とともに投げることが出来ます。ちなみに「投げる」というのはthrowするという意味です。

実際には、どんな例外も受け取るExceptionクラスを使用しても良いのですが、個別に例外をキャッチするとエラーハンドルがやりやすいと思います。

try{処理}catch(例外の種類){エラー処理}のようにcatchの部分にキャッツする例外を記述します。

見やすくするとこんな感じ

スクリーンショット 2018-10-21 18.44.41.png

サンプルコードはこちら

実装例

try-catch文を場合分けして、サンプルコードを書きました。色々な例外クラスがあるのでJavaDocで調べてみるのも一つです。

例1: 標準入力を受け取るのに例外が投げられる可能性がある時

入出力系の例外はIOExceptionでキャッチします。

// try部分に例が発生するメソッド処理を記載するtry {

   System.in.read(b);

} catch(IOException e) {

   // 例外が起きた時にはキャッチ文ところで処理

   e.printStackTrace();

}

キャッチする例外を分けたい場合は
対応する例外クラスがJavaAPIにあるのでそれをキャッチするように
します。

例2: 例外を別々に受け取る

入出力系の例外とそのほかの例外を場合分けしてキャッチする実装です。

// 5バイト(5文字)分
byte[] b = new byte[5];

try {

   // 入出力の例外を投げる

   System.in.read(b);

  // 文字列を受け取る

  String result = new String(b);

  // 文字列に'a'が見つからない場合

 if (result.indexOf("a") == -1) {

     // 例外を投げる

    throw new Exception("入力違反です");
  }

} catch(IOException ie) {

   // 初めに標準入力の例外を受け取る様にする

   ie.printStackTrace();

} catch(Exception e) {

   // 自分で投げる例外をキャッチ
 
   e.printStackTrace();

}

ちなみに例外を扱う方法は他にもあって
メソッドで「例外をなげますよ」と指定する方法があります。

// Exceptionを投げる可能性があるメソッドを示す
public void testException() throws Exception {
  // 何かの処理
}

この時にはtry catch文は記載する必要がありませんが
このメソッドを呼び出す側がtry catchする必要があります。

そして、以下の様な場合はmainメソッドで例外を検知できません。

public static void main(String[] args) {

   testPrint();

}


/**

 * メインメソッドから直接(クラスをnew しないで)呼び出す時

 * はメソッドの修飾子に「static」をつける

 */

public static void testPrint() {

   try {

      throw new Exception("必ず例外を投げます");

   } catch(Exception e) {

     e.printStackTrace();

   }
}

呼び出し元に例外を検知させたくない場合に
上記の様な書き方を行います。

関連ページ

  1. 標準入力(コンソールからの入力)<System.inクラスについて>
  2. サンプル実装〜コンソールゲーム〜
  3. Java Basic インターフェース・抽象クラスの作り方
  4. Java Basic クラスとは〜Step2_1〜

 



関連ページ