「Map値抽出」は“辞書の中身だけを取り出す”イメージ
Map<K, V> は「キー → 値」の対応表です。
業務では「ユーザーID → ユーザー情報」「商品コード → 商品情報」など、ほぼ必ず出てきます。
その中で「値だけ欲しい」「キーはいらない」という場面がかなり多いです。
たとえば「ユーザー情報一覧が欲しい」「商品情報だけを別処理に渡したい」など。
この「Map から値だけを安全に・分かりやすく取り出す」のが、今回のテーマです。
基本形:values で値の“ビュー”を取り出す
Map#values の挙動を正しく理解する
一番基本は Map#values() です。
import java.util.HashMap;
import java.util.Map;
import java.util.Collection;
public class ValuesBasic {
public static void main(String[] args) {
Map<String, String> userMap = new HashMap<>();
userMap.put("u001", "山田");
userMap.put("u002", "佐藤");
userMap.put("u003", "鈴木");
Collection<String> values = userMap.values();
System.out.println(values); // [山田, 佐藤, 鈴木] のようなイメージ
}
}
Javaここで重要なのは、「values() も“ビュー”である」という点です。
ビューというのは、「元の Map と中身を共有している“見え方だけのコレクション”」という意味です。
つまり、userMap に要素を追加・削除すると、values にも反映されます。
逆に、values.remove("山田") のように値コレクションから削除すると、元の userMap からもそのエントリが消えます。
「値一覧を眺めるだけ」ならビューで問題ありませんが、
「独立したコレクションとして扱いたい」場合はコピーが必要になります。
List として値を扱いたいときのユーティリティ
Collection ではなく List が欲しい場面は多い
values() の戻り値は Collection<V> です。
しかし業務では、「List として扱いたい」ことが多いです。
たとえば「ソートしたい」「先頭 N 件だけ取りたい」「Stream に流したい」など。
その場合は、values() から List を作るユーティリティを用意しておくと便利です。
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public final class MapValues {
private MapValues() {}
public static <K, V> List<V> toList(Map<K, V> map) {
if (map == null || map.isEmpty()) {
return List.of();
}
return new ArrayList<>(map.values());
}
}
Java使い方はこうです。
Map<String, String> userMap = Map.of(
"u001", "山田",
"u002", "佐藤",
"u003", "鈴木"
);
List<String> userNames = MapValues.toList(userMap);
System.out.println(userNames); // [山田, 佐藤, 鈴木] など
Javaここでの重要ポイントは二つです。
一つ目は、「new ArrayList<>(map.values()) で“独立した List”を作っている」ことです。
これにより、元の Map を変更しても List 側は変わりませんし、List を変更しても Map には影響しません。
二つ目は、「null や空 Map の扱いをユーティリティ側で決めている」ことです。
呼び出し側は「値一覧が欲しい」とだけ考えればよく、毎回 null チェックを書く必要がなくなります。
ソートされた値一覧が欲しいとき
値を自然順・任意順で並べ替える
「値一覧を画面に表示する」「ログに出す」などの場面では、
ソートされた順番で扱いたいことが多いです。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public final class MapValues {
private MapValues() {}
public static <K, V extends Comparable<? super V>> List<V> sorted(Map<K, V> map) {
if (map == null || map.isEmpty()) {
return List.of();
}
List<V> list = new ArrayList<>(map.values());
Collections.sort(list); // 値の自然順でソート
return list;
}
}
Java使い方はこうです。
Map<String, Integer> scores = Map.of(
"山田", 80,
"佐藤", 90,
"鈴木", 70
);
List<Integer> sortedScores = MapValues.sorted(scores);
// [70, 80, 90]
Javaここでの重要ポイントは、
「値が Comparable を実装している前提で自然順ソートしている」ことです。
独自の順番で並べたいなら、Comparator を受け取るオーバーロードを用意できます。
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
public static <K, V> List<V> sorted(
Map<K, V> map,
Comparator<? super V> comparator
) {
if (map == null || map.isEmpty()) {
return List.of();
}
List<V> list = new ArrayList<>(map.values());
list.sort(comparator);
return list;
}
Java条件付きで値を抽出する(フィルタ+値抽出)
「キーに基づいて値を取りたい」パターン
「値だけ欲しい」といっても、
「全部」ではなく「特定のキーに合致する値だけ欲しい」こともあります。
たとえば「ID が特定のパターンのものだけの値一覧」などです。
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public final class MapValues {
private MapValues() {}
public static <K, V> List<V> valuesWhereKey(
Map<K, V> map,
java.util.function.Predicate<? super K> keyCondition
) {
if (map == null || map.isEmpty()) {
return List.of();
}
return map.entrySet().stream()
.filter(e -> keyCondition.test(e.getKey()))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
}
}
Java使い方の例です。
Map<String, Integer> scores = Map.of(
"A001", 80,
"B002", 90,
"A003", 70
);
// キーが "A" で始まるもののスコアだけ
List<Integer> aScores =
MapValues.valuesWhereKey(scores, k -> k.startsWith("A"));
System.out.println(aScores); // 例: [80, 70]
Javaここで深掘りしたい重要ポイントは三つです。
一つ目は、「entrySet().stream() から filter → map(getValue) という流れで、“キーで絞って値を取り出す”処理を素直に書いている」ことです。
二つ目は、「Predicate<? super K> keyCondition が“どんなキーのときに値を採用するか”を表している」ことです。k -> k.startsWith("A") のように、業務ルールをラムダで渡せます。
三つ目は、「値抽出とフィルタをユーティリティに閉じ込めることで、呼び出し側のコードが“何をしたいか”だけに集中できる」ことです。
Stream を使った値抽出の基本パターン
「Map → values / entrySet → Stream → 値一覧」の流れに慣れる
Stream を使うと、値抽出は次のような基本形になります。
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Map<String, Integer> scores = Map.of(
"山田", 80,
"佐藤", 90,
"鈴木", 70
);
// 値だけの List
List<Integer> allScores =
scores.values().stream()
.collect(Collectors.toList());
// キー条件で絞った値だけ
List<Integer> yamadaScoreOnly =
scores.entrySet().stream()
.filter(e -> e.getKey().equals("山田"))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
Javaここでの重要ポイントは二つです。
一つ目は、「全部の値が欲しいだけなら values().stream() で十分」ということです。
二つ目は、「キーや値の条件で絞りたいときは entrySet().stream() → filter → map(getValue) が基本形」ということです。
このパターンに慣れると、Map を使った処理がかなり読みやすくなります。
まとめ:Map値抽出ユーティリティで身につけてほしい感覚
Map値抽出は、
単に「values を呼ぶテクニック」ではなく、
「Map という“辞書”から、必要な中身だけを安全に・意図通りに取り出す技術」です。
values() はビューであり、元の Map と中身を共有することを理解する。
独立したコレクションとして扱いたいときは、new ArrayList<>(map.values()) のようにコピーを作る。MapValues.toList や MapValues.sorted のようなユーティリティにして、null・空・ソート方針を一箇所に閉じ込める。
「キーの条件で値を抽出する」場合は、entrySet().stream() → filter → map(getValue) の流れを基本パターンとして覚える。
あなたのコードのどこかに、
毎回 for (var e : map.entrySet()) { values.add(e.getValue()); } と手書きしている箇所があれば、
それを一度「Map値抽出ユーティリティ+Stream」に置き換えられないか眺めてみてください。
その小さな整理が、
「Map から“欲しい値だけ”を迷いなく取り出せるエンジニア」への、
確かな一歩になります。
