java Map 추가된 method

만년 쭈글이 개발자·2022년 10월 24일
0

TIL

목록 보기
9/13

HashMap은 자주 쓰는데 1.8에 추가된 메소드들이 있는데(주로 람다 관련인듯..)
사용 방법을 잘 몰라서 잘 안썼습니다. 그런데 활용하면 좋아보이는 것들이 많아서
한번 정리해보면 코드 짤 때 잘 생각날듯 싶어서 개인적으로 이해한 내용을 정리해보았습니다.

Methods들

기본 methods

제가 자주 쓰던 기본 메소드들은 걍 간단하게만 정리했습니다.
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

putAll(Map<? extends K,? extends V> m)
Copies all of the mappings from the specified map to this map.

map을 인자로 받아서 해당 map이 가지는 key-value 값들을 전부 추가해줍니다.

  • 기존에 있던 key-value 쌍은 인자로 넘어오는 map에 있는 key-value로 바뀜

putIfAbsent

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.

  • key값이 map에 없는 경우 또는 key값에 value가 null로 매핑되어있는 경우에만 put

merge

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;
    }

요약

  • value값 또는 remappingFunction이 null 이면 NullPointerException
  • key값이 존재하지 않으면 key-value를 넣어준다.
  • remappingFunction이 받는 인자는 old.value 와 value를 받아서 value값을 반환
    (주의 : return값이 null 이 되는 경우 값이 아래 널체크에 걸려서 갱신되지 않음)
  • 기존 value에 새 key-value를 이용하여 연산하는 등의 과정이 필요할 때 사용하면 좋을듯

compute

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).

  • compute는 '계산하다'라는 의미 - key값에 대해 어떻게 연산할것인지를 정의
    인자로 key값과 remappingFuction을 받는다.
  • remappingFuction이 null 이면 NullPointerException
  • remappingFuction은 key, value[기존값]를 받아서 연산한 결과 value를 return하는 함수
    연산 결과 return값이 null인 경우, 기존의 mapping 된 key-value는 삭제된다.
  • remappingFunction 처리중 에러가 나는 경우 기존의 key-value mapping은 유지됨
  • key값에 해당되는 값이 있든 없든 연산처리후의 값으로 value가 갱신된다.

computeIfAbsent

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.

  • compute와 동일하지만, key값에 해당되는 값이 없는 경우에만 연산을 수행

computeIfPresent

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.

  • key값에 해당되는 값이 있는 경우에만 연산을 수행
  • 기존 value들을 갱신처리해야 하는 경우 유용

getOrDefault

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.

  • key값으로 map에 해당 value가 존재하지 않는 경우, defaultValue를 반환한다.(get은 기본 null)

replace

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

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.

  • map의 기존 key-value 값들을 전부 바꿔줌(function의 return 값으로)
  • function은 key, value를 받아서 value를 return하는 함수
  • map의 size가 0보다 큰 경우만 수행된다.
profile
오늘의 나는 내일의 나보다 젊지

0개의 댓글