HashMap은 자주 쓰는데 1.8에 추가된 메소드들이 있는데(주로 람다 관련인듯..)
사용 방법을 잘 몰라서 잘 안썼습니다. 그런데 활용하면 좋아보이는 것들이 많아서
한번 정리해보면 코드 짤 때 잘 생각날듯 싶어서 개인적으로 이해한 내용을 정리해보았습니다.
제가 자주 쓰던 기본 메소드들은 걍 간단하게만 정리했습니다.
key값들은 중복될수 없고, 같은 key 값에 여러 value는 불가능, 다른 key 값에 같은 value는 가능
//선언
HashMap<K, V> map = new HashMap<>();
//key-value 쌍을 넣어주기
map.put(key, value);
//삭제
map.remove(key);
//key의 개수
map.size();
//해당 key가 가지는 value 반환, 없는 경우 null
map.get(Object key)
//key값들을 Set<K> 형태로 반환
map.keySet();
//value 값들을 Collection<V>형태로 반환
map.values();
putAll(Map<? extends K,? extends V> m)
Copies all of the mappings from the specified map to this map.
map을 인자로 받아서 해당 map이 가지는 key-value 값들을 전부 추가해줍니다.
putIfAbsent(K key, V value)
If the specified key is not already associated with a value (or is mapped to null) associates it with the given value and returns null, else returns the current value.
merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value.
인자로 key, value, 람다식(remappingFunction)을 받습니다.
이름이 merge라서 map끼리 합칠 것 같았지만 아님(...)
public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
if (value == null)
throw new NullPointerException();
if (remappingFunction == null)
throw new NullPointerException();
int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i;
int binCount = 0;
TreeNode<K,V> t = null;
// 키값이 존재하면 old값을 넣어줌
Node<K,V> old = null;
if (size > threshold || (tab = table) == null ||
(n = tab.length) == 0)
n = (tab = resize()).length;
if ((first = tab[i = (n - 1) & hash]) != null) {
if (first instanceof TreeNode)
old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
else {
Node<K,V> e = first; K k;
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
old = e;
break;
}
++binCount;
} while ((e = e.next) != null);
}
}
if (old != null) {
V v;
if (old.value != null) {
int mc = modCount;
// 기존에 존재하는 key-value 쌍이 있다면 remappingFuction으로 처리된 값으로 value 갱신
v = remappingFunction.apply(old.value, value);
if (mc != modCount) {
throw new ConcurrentModificationException();
}
} else {
//여기서 key에 해당되는 value값이 없으면 v는 인자로 넘어오는 value가 됨
v = value;
}
if (v != null) {
old.value = v;
afterNodeAccess(old);
}
else
removeNode(hash, key, null, false, true);
return v;
}
// 최종적으로 value값이 null이 아닌 경우만 갱신
if (value != null) {
if (t != null)
// key값과 value를 넣어준다
t.putTreeVal(this, tab, hash, key, value);
else {
tab[i] = newNode(hash, key, value, first);
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
}
++modCount;
++size;
afterNodeInsertion(true);
}
return value;
}
요약
compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping).
computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
If the specified key is not already associated with a value (or is mapped to null), attempts to compute its value using the given mapping function and enters it into this map unless null.
computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
If the value for the specified key is present and non-null, attempts to compute a new mapping given the key and its current mapped value.
getOrDefault(Object key, V defaultValue)
Returns the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key.
replace(K key, V value)
Replaces the entry for the specified key only if it is currently mapped to some value.
put과 replace는 무슨차이일까? replace가 아닌 put을 써도 결과적으로 value값은 바뀐다.
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with {@code key}, or
* {@code null} if there was no mapping for {@code key}.
* (A {@code null} return can also indicate that the map
* previously associated {@code null} with {@code key}.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
public V replace(K key, V value) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) != null) {
V oldValue = e.value;
e.value = value;
afterNodeAccess(e);
return oldValue;
}
return null;
}
put과는 달리 replace는 key의 value값이 null이 아닌 경우에만 수행된다.
replace된 경우에는 oldValue를 return하고,
key값에 대한 mapping이 없는 경우는 아무것도 하지 않고 null을 return
좀 더 확실하게 기존 key-value 매핑이 있고, 그 값을 변경하는 경우로 한정하여 사용해야 하는 경우에는 replace를 사용하는게 맞는 것 같다(그동안 걍 put을 많이 쓴듯...)
replaceAll(BiFunction<? super K,? super V,? extends V> function)
Replaces each entry's value with the result of invoking the given function on that entry until all entries have been processed or the function throws an exception.