5日目のゴール
5日目のテーマは
「Map を“設定・状態・スコア”を持つための土台として使えるようになること」 です。
ここまでであなたは、
キーで値を引ける
値にオブジェクトを入れられる
Map と List を組み合わせてグループ分けできる
というところまで来ています。
5日目では、もう一歩踏み込んで、
「設定(config)を Map で持つ」
「スコアボードを Map で持つ」
「存在しないキーに対して“デフォルト値”を返す」
という、“アプリの裏側でよく使う Map の顔”を固めていきます。
Map を「設定(config)」として使う
設定ってそもそも何?
アプリには、こんな「設定」がよくあります。
テーマカラー(light / dark)
言語(ja / en)
1ページあたりの表示件数(10 / 20 / 50)
これらは、
「設定名 → 設定値」
という形で表せます。
つまり、Map です。
キー:設定名(String)
値:設定値(String や Integer)
という形になります。
シンプルな設定クラスを作る
まずは「文字列だけで持つ設定」を作ってみます。
import java.util.HashMap;
import java.util.Map;
public class AppConfig {
Map<String, String> values;
AppConfig() {
values = new HashMap<>();
}
void set(String key, String value) {
if (key == null || key.isEmpty()) {
System.out.println("キーは必須です。");
return;
}
values.put(key, value);
}
String get(String key) {
return values.get(key);
}
}
Javaここでやっていることはシンプルです。
Map<String, String> で「設定名 → 設定値」を持つset で put(key, value) するget で get(key) する
でも、これだけだと少し足りません。
「設定がないとき」の扱いを決める
そのまま get すると null が返る
例えば、こう使ったとします。
AppConfig config = new AppConfig();
config.set("theme", "dark");
System.out.println(config.get("theme")); // "dark"
System.out.println(config.get("language")); // null
Javalanguage は設定していないので、null が返ります。
設定としては、
「設定されていないときは、デフォルト値を使いたい」
ということが多いです。
例えば、
theme のデフォルトは “light”
language のデフォルトは “ja”
など。
getOrDefault という考え方
「なければデフォルト」を毎回 if で書くのは面倒なので、
メソッドにしてしまいます。
String getOrDefault(String key, String defaultValue) {
String value = values.get(key);
if (value == null) {
return defaultValue;
}
return value;
}
Javaこれで、こう書けます。
String theme = config.getOrDefault("theme", "light");
String language = config.getOrDefault("language", "ja");
Javaここでの重要ポイントは、
「Map は“設定されていない”という状態も持ちうる」
だからこそ、“なければこれ”というデフォルトを決めておくと扱いやすい
ということです。
数値設定を安全に扱う
文字列から数値に変換する
設定値を全部 String で持つと、
「数値として使いたいとき」に変換が必要になります。
例えば「1ページあたりの表示件数」を pageSize というキーで持つとします。
config.set("pageSize", "20");
Javaこれを数値として使いたいときは、こうします。
String raw = config.get("pageSize");
int pageSize;
if (raw == null) {
pageSize = 10; // デフォルト
} else {
try {
pageSize = Integer.parseInt(raw);
} catch (NumberFormatException e) {
pageSize = 10; // 変な値が入っていたらデフォルト
}
}
Java少し長いですが、やっていることはこうです。
設定がなければデフォルト
あっても数値に変換できなければデフォルト
つまり、
「Map は“何でも入る箱”だからこそ、取り出す側で責任を持って解釈する」
という姿勢が大事になります。
スコアボードを Map で作る
「名前 → スコア」の世界
次は、ゲームのスコアボードを考えてみます。
“alice” → 1200
“bob” → 800
“charlie” → 1500
これはそのまま、
Map<String, Integer>
です。
キー:プレイヤー名
値:スコア
という形になります。
ScoreBoard クラスを作る
import java.util.HashMap;
import java.util.Map;
public class ScoreBoard {
Map<String, Integer> scores;
ScoreBoard() {
scores = new HashMap<>();
}
void setScore(String name, int score) {
if (name == null || name.isEmpty()) {
System.out.println("名前は必須です。");
return;
}
if (score < 0) {
System.out.println("スコアは 0 以上にしてください。");
return;
}
scores.put(name, score);
}
Integer getScore(String name) {
return scores.get(name);
}
}
Javaここまでは、2日目のカウンターと似ていますね。
「今のスコアより高いときだけ更新する」
ハイスコアの考え方
ゲームでは、
「今回のスコアが、今までのハイスコアより高いときだけ更新する」
というルールがよくあります。
これを Map で書いてみます。
void updateHighScore(String name, int newScore) {
if (name == null || name.isEmpty()) {
System.out.println("名前は必須です。");
return;
}
if (newScore < 0) {
System.out.println("スコアは 0 以上にしてください。");
return;
}
Integer current = scores.get(name);
if (current == null || newScore > current) {
scores.put(name, newScore);
System.out.println(name + " のハイスコアを " + newScore + " に更新しました。");
} else {
System.out.println(name + " のハイスコアは " + current + " のままです。");
}
}
Javaここでの重要ポイントは、
キーが存在しない(初登場のプレイヤー)なら、そのまま登録
キーが存在するなら、「今の値」と「新しい値」を比較して、条件付きで上書き
というロジックを、
Map の上に素直に乗せていることです。
「Map は“今の状態”を持つ場所であり、put は“状態の更新”」
という感覚が、ここでさらに強くなります。
スコアボードを一覧表示する
keySet で回す
void showAll() {
System.out.println("=== スコアボード ===");
if (scores.isEmpty()) {
System.out.println("まだスコアが登録されていません。");
return;
}
for (String name : scores.keySet()) {
int score = scores.get(name);
System.out.println(name + " : " + score);
}
}
Javaここはもう、だいぶ見慣れた形ですね。
Map の中身を「全部なめる」ときは、
keySet() でキー一覧を取り出す
キーから get(key) で値を取り出す
というパターンです。
5日目のミニアプリ:設定+スコアボード
AppConfig と ScoreBoard を一緒に使う
最後に、今日の内容をまとめて動かしてみます。
public class Main {
public static void main(String[] args) {
AppConfig config = new AppConfig();
config.set("theme", "dark");
config.set("language", "ja");
config.set("pageSize", "20");
String theme = config.getOrDefault("theme", "light");
String language = config.getOrDefault("language", "en");
String pageSizeRaw = config.getOrDefault("pageSize", "10");
int pageSize;
try {
pageSize = Integer.parseInt(pageSizeRaw);
} catch (NumberFormatException e) {
pageSize = 10;
}
System.out.println("=== 設定 ===");
System.out.println("theme : " + theme);
System.out.println("language : " + language);
System.out.println("pageSize : " + pageSize);
ScoreBoard board = new ScoreBoard();
board.updateHighScore("alice", 1200);
board.updateHighScore("bob", 800);
board.updateHighScore("alice", 900); // 更新されない
board.updateHighScore("alice", 1500); // 更新される
board.showAll();
}
}
Javaこの Main を眺めてみてください。
設定を Map で持つ
「なければデフォルト」という考え方で取り出す
スコアボードを Map で持つ
「今より良いときだけ更新」というロジックを Map の上に乗せる
ここにも、Map という単語はほとんど出てきません。
見えているのは、
設定
テーマ
言語
ページサイズ
スコアボード
ハイスコア
という「アプリの世界」です。
裏側では、
Map<String, String> が設定をMap<String, Integer> がスコアを
それぞれ key/value の形で支えています。
5日目で絶対に押さえてほしい本質
今日いちばん大事なのは、
「Map は“設定・状態・スコア”のような“今の値”を持つ場所として、とても相性がいい」
という感覚です。
設定名 → 設定値
プレイヤー名 → ハイスコア
ユーザーID → 現在のステータス
どれも形は同じです。
キーは「何を知りたいか」
値は「そのときの答え」
そして、
put は「答えの更新」get は「今の答えの参照」
「なければデフォルト」という考え方をセットで持つ
ここまで見えてきたら、
Map はもう「ただの key/value の入れ物」ではなく、
「アプリの“今”を表現するための中枢」 に見えてくるはずです。
次のステップでは、
これを List や他のクラスと組み合わせて、
さらに大きな「アプリの世界」を組み立てていけます。


