未来エンジニア養成所Blog

月単価180万以上のプログラミング講師がプログラミングを皆に楽しんでもらうための情報をお届けします。

【Java】オブジェクト指向の応用問題3-5

title


問題3-5

宝物を表現するTreasureクラスと、金庫を表現するStrongBoxクラス、秘密の言葉に関する例外を表現するIllegalSecretException例外クラスとDuplicateSecretException例外クラスを作成してください。


その4つのクラスを使用するHashMapNormalPracticeクラスのmainメソッドはすでに完成しています。
(変更は禁止です)


【Treasureクラス】

  1. 宝物のタイプを表現するtypeインスタンスフィールド(String型)を定義します。

  2. タイプの値を受け取るコンストラクタを定義します。
    タイプの値をインスタンスフィールドに設定します。

  3. オブジェクトの文字列表現を返すためのtoStringメソッドをオーバーライドします。
    戻り値として返す値は、typeインスタンスフィールドの値そのものです。


【IllegalSecretException例外クラスとDuplicateSecretException例外クラス】

  1. 検査例外なのでExceptionクラスを継承します。

  2. クラスの中は空っぽで良いです。


【StrongBoxクラス】

  1. HashMap<String, Treasure>型の宝物保持HashMapインスタンスフィールドtreasureを定義します。
    キーのString型は、秘密の言葉を表現します。

  2. 引数なしコンストラクタを定義します。
    宝物保持HashMapインスタンスフィールドtreasuresのオブジェクトをここで生成してください。

  3. 秘密の言葉と宝物を金庫に格納するstoreメソッドを定義します。
    第一引数は秘密の言葉(String型)、第二引数は宝物オブジェクト(Treasure型)です。
    戻り値はなしです。
    検査例外DuplicateSecretExceptionをスローする可能性があるので、throwsが必要です。
    まず、引数で渡ってきた秘密の言葉がすでに使用されているかをチェックします。
    すでに使用されている場合は、DuplicateSecretExceptionのインスタンスを生成し、スローします。
    秘密の言葉がまだ使用されていない場合は、「○○を金庫に格納しました!」と出力し、HashMapインスタンスフィールドtreasuresに秘密の言葉をキーとして宝物オブジェクトを格納してください。

  4. 秘密の言葉に対する宝物オブジェクトを取得するgetTreasureメソッドを定義します。
    引数は秘密の言葉(String型)、戻り値は宝物オブジェクト(Treasure型)です。
    検査例外IllegalSecretExceptionをスローする可能性があるので、throwsが必要です。
    HashMapインスタンスフィールドtreasureから、秘密の言葉を元に宝物オブジェクトを取得し、戻り値として返します。
    もし秘密の言葉が不正の場合は、HashMapオブジェクトはnullを返すので、その場合はIllegalSecretExceptionのインスタンスを生成し、スローします。


【実行結果】

ダイヤの指輪を金庫に格納しました!
真珠のネックレスを金庫に格納しました!
金のブレスレットを金庫に格納しました!
秘密の言葉「xrt03」はすでに使われています

ダイヤの指輪をゲットしました!
真珠のネックレスをゲットしました!
秘密の言葉「xrr03」は不正です


【HashMapNormalPractice.java】

public class HashMapNormalPractice {
    public static void main(String[] args) {

        // 金庫インスタンスの作成
        StrongBox guard = new StrongBox();

        // 秘密の言葉変数の宣言
        String secret = null;

        try {
            // 1つ目の宝物を格納
            secret = "sgf01";
            guard.store(secret, new Treasure("ダイヤの指輪"));

            // 2つ目の宝物を格納
            secret = "zkq02";
            guard.store(secret, new Treasure("真珠のネックレス"));

            // 3つ目の宝物を格納
            secret = "xrt03";
            guard.store(secret, new Treasure("金のブレスレット"));

            // 4つ目の宝物を格納(秘密の言葉が重複)
            secret = "xrt03";
            guard.store(secret, new Treasure("プラチナのイヤリング"));

        } catch(DuplicateSecretException e) {
            System.out.println("秘密の言葉「" + secret + "」はすでにつかわれています");
        }

        System.out.println();

        try {
            // 1つ目の宝物を取得
            secret = "sgf01";
            Treasure treasure1 = guard.getTreasure(secret);
            System.out.println(treasure1 + "をゲットしました!");

            // 2つ目の宝物を取得
            secret = "zkq02";
            Treasure treasure2 = guard.getTreasure(secret);
            System.out.println(treasure2 + "をゲットしました!");

            // 3つ目の宝物を取得(秘密の言葉が不正)
            secret = "xrr03";
            Treasure treasure3 = guard.getTreasure(secret);
            System.out.println(treasure3 + "をゲットしました!");

        } catch(IllegalSecretException e) {
            System.out.println("秘密の言葉「" + secret + "」は不正です");
        }

    }
}


// ここに宝物クラスを作成してください


// ここに秘密の言葉不正例外クラスを作成してください


// ここに秘密の言葉重複例外クラスを作成してください


// ここに金庫クラスを作成してください


解答例

【HashMapBasicPractice.java】

import java.util.HashMap;

public class HashMapNormalPractice {
    public static void main(String[] args) {

        // 金庫インスタンスの作成
        StrongBox guard = new StrongBox();

        // 秘密の言葉変数の宣言
        String secret = null;

        try {
            // 1つ目の宝物を格納
            secret = "sgf01";
            guard.store(secret, new Treasure("ダイヤの指輪"));

            // 2つ目の宝物を格納
            secret = "zkq02";
            guard.store(secret, new Treasure("真珠のネックレス"));

            // 3つ目の宝物を格納
            secret = "xrt03";
            guard.store(secret, new Treasure("金のブレスレット"));

            // 4つ目の宝物を格納(秘密の言葉が重複)
            secret = "xrt03";
            guard.store(secret, new Treasure("プラチナのイヤリング"));

        } catch(DuplicateSecretException e) {
            System.out.println("秘密の言葉「" + secret + "」はすでにつかわれています");
        }

        System.out.println();

        try {
            // 1つ目の宝物を取得
            secret = "sgf01";
            Treasure treasure1 = guard.getTreasure(secret);
            System.out.println(treasure1 + "をゲットしました!");

            // 2つ目の宝物を取得
            secret = "zkq02";
            Treasure treasure2 = guard.getTreasure(secret);
            System.out.println(treasure2 + "をゲットしました!");

            // 3つ目の宝物を取得(秘密の言葉が不正)
            secret = "xrr03";
            Treasure treasure3 = guard.getTreasure(secret);
            System.out.println(treasure3 + "をゲットしました!");

        } catch(IllegalSecretException e) {
            System.out.println("秘密の言葉「" + secret + "」は不正です");
        }

    }
}

// 宝物クラス
class Treasure {

    // タイプ
    private String type;

    // コンストラクタ
    public Treasure(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return type;
    }
}

// 秘密の言葉不正例外クラス
class IllegalSecretException extends Exception {}

// 秘密の言葉重複例外クラス
class DuplicateSecretException extends Exception {}

// 金庫クラス
class StrongBox {

    // 宝物保持マップ
    private HashMap<String, Treasure> treasures;

    // コンストラクタ
    public StrongBox() {
        treasures = new HashMap<String, Treasure>();
    }

    // 秘密の言葉と宝物を金庫に格納する
    public void store(String secret, Treasure treasure) throws DuplicateSecretException {

        // すでに秘密の言葉が使用済みの場合
        if(treasures.containsKey(secret)) {

            // 秘密の言葉重複例外をスローする
            throw new DuplicateSecretException();
        } else {
            System.out.println(treasure + "を金庫に格納しました!");

            // 金庫に宝物を格納する
            treasures.put(secret, treasure);
        }
    }

    // 秘密の言葉で宝物を取り出す
    public Treasure getTreasure(String secret) throws IllegalSecretException {

        // 秘密の言葉を使って宝物保持マップから宝物を取得
        Treasure treasure = treasures.get(secret);

        // 秘密の言葉が不正の場合
        if(treasure == null) {

            // 秘密の言葉不正例外をスローする
            throw new IllegalSecretException();

        } else {

            // 宝物を戻り値として返す
            return treasure;
        }
    }
}


解説

List系コレクションは要素を追加していくので、そのたびにインデックス番号がインクリメントして割り当てられます。

しかしMap系コレクションはインデックス番号の代わりにキーを用いるので、すでに使われているとか、キーが不正といったトラブルを招きます。

今回の問題はそのあたりにスポットを当てています。



宝物を格納するための金庫クラスは秘密の言葉で宝物を管理します。


まずはstoreメソッドで金庫に宝物を格納するのですが、その時に使用する秘密の言葉がすでに使われていないかチェックする必要があります。

もしチェックせずにMapのputメソッドを使って登録してしまうと、そのキーに対する値は上書きになり、戻り値として古い値を返す仕様になっています。


今回はMapのcontainsKeyメソッドを使ってキーがすでに使われているかをチェックしました。引数はキー、戻り値はboolean型で重複している場合にtrueとなります。

今回はif文の中でcontainsKeyメソッドを呼び出し、trueなら秘密の言葉重複例外DuplicateSecretExceptionをスローしました。

falseであれば新規にキーと値をputメソッドを用いて登録するだけです。



金庫から宝物を取り出すには、getTreasureメソッドを使用します。

内部的にはMapのgetメソッドを使います。

引数はキー、戻り値は値なのですが、もしキーが不正ならnullを返します。

戻り値がnullなら、秘密の言葉不正例外IllegalSecretExceptionをスローしています。



コレクションフレームワークを使用する場合は、JavaのAPIドキュメントをよく読んでみてください。

たくさんの便利なメソッドが定義されていますので、どんどん活用していきましょう。


参考図書



LINE公式アカウント

仕事が辛くてたまらない人生が、仕事が楽しくてたまらない人生に変わります。
【登録いただいた人全員に、無料キャリア相談プレゼント中!】


LineOfficial

友だち追加



【まついのLINE公式アカウントはこちらから!】
Line公式アカウント