Java 8 HashMap
3973 ワード
HashMapは、配列、チェーンテーブル、および赤黒ツリーを使用してキー値ペアを格納し、チェーンテーブルが十分に長い場合は赤黒ツリーに変換します.HashMapは非スレッドで安全です.
HashMapの定数
HashMapの容量はシフト動作に用いられ,1個の数aをnビット左にシフトすることは,a=a*2 nに相当するので,1<<4=>1*24=16である.したがって、HashMapの容量は常に2のn乗である.
パラメトリック構造法を使用して、初期容量と充填係数を指定します.指定した容量は2のn乗に上方に調整されます(たとえば、指定した容量が13の場合、16に調整されます).
HashMapのキー値ペアの値はnullであってもよく、keyがnullのキー値ペアが存在してもよい.
HashMapの一部の方法
treeifyBinメソッド
ここでの(n−1)&hashはhash%nに相当する余剰演算であり,HashMapの長さは常に2のn乗であるからである.
replaceAllメソッド
このメソッドは、lambda式を受け入れ、所定の条件を満たす値を置き換えます.たとえば、次のようにします.
forEachメソッド
この方法は、キー値ペアを消費するためのlambda式も受け入れます.
HashMapの定数
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;
static final int MIN_TREEIFY_CAPACITY = 64;
DEFAULT_INITIAL_CAPACITY
初期容量は16である.MAXIMUM_CAPACITY
の最大容量は230です.DEFAULT_LOAD_FACTOR
デフォルトの充填係数.初期の場合、キー値ペア数が16*充填因子より大きいと、元の2倍に拡張されます.TREEIFY_THRESHOLD
チェーンテーブルの長さがこの値に達すると、ツリーに変換される可能性があります.UNTREEIFY_THRESHOLD
チェーンテーブル長がこの値より小さい場合、ツリーからチェーンテーブルに劣化します.MIN_TREEIFY_CAPACITY
ツリーに移行する前に、キー値ペアの数がこの値より大きい場合にのみ赤黒ツリーに移行し、その値より小さい場合には拡張のみがトリガーされると判断します.HashMapの容量はシフト動作に用いられ,1個の数aをnビット左にシフトすることは,a=a*2 nに相当するので,1<<4=>1*24=16である.したがって、HashMapの容量は常に2のn乗である.
パラメトリック構造法を使用して、初期容量と充填係数を指定します.指定した容量は2のn乗に上方に調整されます(たとえば、指定した容量が13の場合、16に調整されます).
HashMapのキー値ペアの値はnullであってもよく、keyがnullのキー値ペアが存在してもよい.
HashMapの一部の方法
treeifyBinメソッド
/**
* Replaces all linked nodes in bin at index for given hash unless
* table is too small, in which case resizes instead.
*/
final void treeifyBin(Node[] tab, int hash) {
int n, index; Node e;
//
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize(); //
else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode hd = null, tl = null;
do {
TreeNode p = replacementTreeNode(e, null);
if (tl == null)
hd = p;
else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while ((e = e.next) != null);
if ((tab[index] = hd) != null)
hd.treeify(tab);
}
}
put
メソッドを呼び出してキー値ペアを追加すると、数がTREEIFY_THRESHOLD
に達するとtreeifyBin
メソッドが呼び出され、このメソッドはテーブル長がMIN_TREEIFY_CAPACITY
に達するかどうかを再判断し、達成されなければ拡張操作のみを行い、そうでなければテーブルをツリーに変換します.ここでの(n−1)&hashはhash%nに相当する余剰演算であり,HashMapの長さは常に2のn乗であるからである.
replaceAllメソッド
@Override
public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
Node[] tab;
if (function == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node e = tab[i]; e != null; e = e.next) {
e.value = function.apply(e.key, e.value);
}
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
このメソッドは、lambda式を受け入れ、所定の条件を満たす値を置き換えます.たとえば、次のようにします.
HashMap map = ...;
// key "foo"
map.replaceAll((k, v) -> k % 2 == 0 ? "foo" : v);
forEachメソッド
@Override
public void forEach(BiConsumer super K, ? super V> action) {
Node[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node e = tab[i]; e != null; e = e.next)
action.accept(e.key, e.value);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
この方法は、キー値ペアを消費するためのlambda式も受け入れます.
//
map.forEach(
(k, v) -> System.out.println(k + ": " + v)
);
// key
map.forEach(
(k, v) -> {
if (k % 2 == 0)
System.out.println(k + ": " + v)
}
);