マップは一連のキーと値のペアで構成される構造化データであり、各キーは 1 つのマップ内で 1 回しか使用できないことに 注意してください。このトピックでは、Java でのMapとその実装クラスの使用に関する 9 つの基本的な質問について説明します。わかりやすくするために、例では一般化を使用します。そこでMap指定子は指定せずに単純にMapと書きます。ただし、 KとVの両方の値が同等であると仮定できます。これは、 K がComparable を拡張し、VもComparable を拡張することを意味します。
0. マップをリストに変換する
Java では、Mapインターフェイスは、キー セット、値セット、キーと値のセットの 3 種類のコレクションを提供します。それらはすべて、コンストラクターまたはメソッドを使用してリストに変換できますaddAll()
。次のコード スニペットは、 Map から ArrayListを作成する方法を示しています。
// list of keys
List keyList = new ArrayList(Map.keySet());
//list of values
List valueList = new ArrayList(Map.valueSet());
//list key-value
List entryList = new ArrayList(Map.entrySet());
1. マップ内のすべての値をループします。
各キーと値のペアを確認することは、マップを確認するための最も基本的な手順です。Java では、各ペアはMap.Entryと呼ばれる Map フィールドに格納されます。Map.entrySet()
はキーと値のセットを返すため、Map のすべての値を反復処理する最も効率的な方法は次のようになります。
for(Entry entry: Map.entrySet()) {
//get the key
K key = entry.getKey();
//get value
V value = entry.getValue();
}
Iterator
特に JDK 1.5 より前のバージョンでは、 を使用することもできます。
Iterator itr = Map.entrySet().iterator();
while(itr.hasNext()) {
Entry entry = itr.next();
//get the key
K key = entry.getKey();
//get value
V value = entry.getValue();
}
2. キーによるマップの順序付け
キーごとにマップを整理することもよく使用される手順です。1 つ目の方法は、Map.Entry をリストに追加し、値で並べ替えるコンパレーターを使用して並べ替えます。List list = new ArrayList(Map.entrySet());
Collections.sort(list, new Comparator() {
@Override
public int compare(Entry e1, Entry e2) {
return e1.getKey().compareTo(e2.getKey());
}
});
別の方法: SortedMapを使用すると、さらにキーが順番に配置されます。ただし、すべてのキーはComparable を具体化するか、コンパレータによって受け入れられる必要があります。実装されたクラスの 1 つはTreeMapSortedMap
です。そのコンストラクターはコンパレーターを受け入れます。次のコードは、通常のものを順序付けされたものに 変換する方法を示しています。Map
SortedMap sortedMap = new TreeMap(new Comparator() {
@Override
public int compare(K k1, K k2) {
return k1.compareTo(k2);
}
});
sortedMap.putAll(Map);
3. 値によるマップの順序付け
この場合、マップをリストに追加して並べ替えると機能しますが、今回は を使用する必要がありますEntry.getValue()
。以下のコードは以前とほぼ同じです。
List list = new ArrayList(Map.entrySet());
Collections.sort(list, new Comparator() {
@Override
public int compare(Entry e1, Entry e2) {
return e1.getValue().compareTo(e2.getValue());
}
});
この場合でもそれを使用できますSortedMap
が、値が一意である場合に限ります。この場合、キーと値のペアをキーと値に変換できます。このソリューションには重大な制限があるため、私はお勧めしません。
4. 静的/不変マップの初期化
マップを不変のままにしたい場合、それを不変のマップにコピーするのが良い方法です。この防御的なプログラミング手法は、安全に使用できるだけでなく、スレッドセーフなマップを作成するのに役立ちます。静的/不変マップを初期化するには、初期化子を使用できますstatic
(以下を参照)。このコードの問題は、Map が として宣言されているにもかかわらずstatic final
、初期化後もそれを操作できることです (たとえば、 ) Test.Map.put(3,"three");
。したがって、それは本当の不変性ではありません。静的初期化子を使用して不変の Map を作成するには、最後の初期化ステップで不変の Map に追加する超匿名クラスが必要です。コードの 2 番目の部分を見てください。を実行するとUnsupportedOperationExceptionがスローされる場合Test.Map.put(3,"three");
。
public class Test {
private static final Map Map;
static {
Map = new HashMap();
Map.put(1, "one");
Map.put(2, "two");
}
}
public class Test {
private static final Map Map;
static {
Map aMap = new HashMap();
aMap.put(1, "one");
aMap.put(2, "two");
Map = Collections.unmodifiableMap(aMap);
}
}
Guava ライブラリは、静的および不変のコレクションを初期化するさまざまな方法もサポートしています。Guava の不変コレクション ユーティリティの利点の詳細については、「Guava How-to」の「不変コレクション」セクションを参照してください。
5. HashMap、TreeMap、Hashtableの違い
Java にはMapインターフェースの主な実装として、 HashMap、TreeMap、およびHashtableの 3 つがあります。主な違いは次のとおりです。- 通過の順序。HashMapと HashTable はマップの順序を保証しません。特に、順序が長期間にわたって同じままであることは保証されません。ただし、
TreeMap
すべての値はキーの「自然な順序」またはコンパレータによって順序付けされます。 - 有効なキーと値のペア。
HashMap
null キーと null 値を持つことができます。HashTable
null キーまたは null 値は許可されません。自然な順序が使用されている場合TreeMap
、またはコンパレータで null キーが許可されていない場合は、例外がスローされます。 - 同期。同期のみ
HashTable
が行われ、残りは同期されません。ただし、「スレッドセーフな実装が必要ない場合は、HashMap
代わりに」を使用することをお勧めしますHashTable
。
. | HashMap | HashTable | TreeMap
-------------------------------------------------------
Упорядочивание |нет |нет | да
null в ключ-meaning | да-да | нет-нет | нет-да
синхронизировано | нет | да | нет
производительность | O(1) | O(1) | O(log n)
воплощение | корзины | корзины | красно-чёрное дерево
HashMap との関係 について詳しくは、こちらをご覧ください。ツリーマップと ハッシュテーブル vs. LinkedHashMap。
6.逆引き検索・表示機能付き地図
場合によっては、キーとキーのペアのセットが必要になります。これは、値がキーと同じくらい一意であることを意味します (1 対 1 のパターン)。この一貫性により、マップ上に「反転ビュー/検索」を作成できます。つまり、その値によってキーを見つけることができます。このデータ構造は双方向 Mapと呼ばれますが、残念ながら JDK ではサポートされていません。Apache Common Collections と Guava はどちらも、それぞれ BidiMap および BiMap と呼ばれる双方向マップ実装を提供します。どちらも、キーと値の間の 1:1 マッピングを強制する制約を導入します。7. マップの浅いコピー
すべてではないにしても、ほぼすべての Java マップには、別のマップのコピー コンストラクターが含まれています。ただし、コピー手順は同期されていません。つまり、あるスレッドがマップをコピーすると、別のスレッドがその構造を変更できるということです。突然のコピー非同期を防ぐために、そのような場合にはいずれかを使用する必要がありますCollections.synchronizedMap()
。
Map copiedMap = Collections.synchronizedMap(Map);
浅くコピーするもう 1 つの興味深い方法は、 を使用することですclone()
。しかし、これは Java コレクション フレームワークの作成者である Joshua Bloch によっても推奨されていません。「コピー コンストラクターとクローン作成」の議論で、彼は次のような立場をとります。 引用: 「人々はパブリック クローン メソッドがそこにあることを期待しているため、私はよく具体的なクラスにパブリック クローン メソッドを提供します。 ... クローン作成が壊れているのは残念ですが、 ...クローン作成は弱点であり、人々はその限界について警告されるべきだと思います。」clone()
このため、 Map をコピーする メソッドの使用方法も示しません。
8. 空のマップを作成する
不変の場合はMap
、次を使用します。
Map = Collections.emptyMap();
あるいは、他の実施形態を使用してもよい。例えば:
Map = new HashMap();
終わり
GO TO FULL VERSION