웹사이트 검색

Java HashMap - Java의 HashMap


Java HashMap은 Java에서 가장 인기 있는 Collection 클래스 중 하나입니다. Java HashMap은 해시 테이블 기반 구현입니다. Java의 HashMap은 Map 인터페이스를 구현하는 AbstractMap 클래스를 확장합니다.

자바 해시맵

  1. Java HashMap은 null 키와 null 값을 허용합니다.
  2. HashMap은 정렬된 컬렉션이 아닙니다. 키 세트를 통해 HashMap 항목을 반복할 수 있지만 HashMap에 추가된 순서가 보장되지는 않습니다.
  3. HashMap은 동기화되지 않고 null 키와 값을 허용한다는 점을 제외하면 Hashtable과 거의 유사합니다.
  4. HashMap은 지도 항목을 저장하기 위해 내부 클래스인 Node를 사용합니다.
  5. HashMap은 항목을 버킷 또는 빈이라는 여러 단일 연결 목록에 저장합니다. 빈의 기본 수는 16이며 항상 2의 거듭제곱입니다.
  6. HashMap은 가져오기 및 넣기 작업을 위해 키에 hashCode() 및 equals() 메서드를 사용합니다. 따라서 HashMap 키 개체는 이러한 메서드의 좋은 구현을 제공해야 합니다. 이것이 String 및 Interger와 같은 불변 클래스가 키에 더 적합한 이유입니다.
  7. Java HashMap은 스레드로부터 안전하지 않습니다. 다중 스레드 환경의 경우 ConcurrentHashMap 클래스를 사용하거나 Collections.synchronizedMap() 메서드를 사용하여 동기화된 맵을 가져와야 합니다.

Java HashMap 생성자

Java HashMap은 네 개의 생성자를 제공합니다.

  1. public HashMap(): 가장 일반적으로 사용되는 HashMap 생성자. 이 생성자는 기본 초기 용량이 16이고 부하율이 0.75인 빈 HashMap을 생성합니다.
  2. public HashMap(int initialCapacity): 이 HashMap 생성자는 초기 용량과 0.75 로드 팩터를 지정하는 데 사용됩니다. 이는 HashMap에 저장할 매핑 수를 알고 있는 경우 재해싱을 방지하는 데 유용합니다.
  3. public HashMap(int initialCapacity, float loadFactor): 이 HashMap 생성자는 지정된 초기 용량 및 로드 팩터를 사용하여 빈 HashMap을 생성합니다. HashMap에 저장할 최대 매핑 수를 알고 있는 경우 이를 사용할 수 있습니다. 일반적인 시나리오에서는 부하 계수 0.75가 공간과 시간 비용 사이에 적절한 절충안을 제공하기 때문에 이를 피해야 합니다.
  4. public HashMap(Map m): 지정된 맵과 동일한 매핑을 갖고 로드 팩터가 0.75인 맵을 생성합니다.

Java HashMap 생성자 예

아래 코드 스니펫은 위의 모든 생성자를 사용하는 HashMap 예제를 보여줍니다.

Map<String, String> map1 = new HashMap<>();

Map<String, String> map2 = new HashMap<>(2^5);

Map<String, String> map3 = new HashMap<>(32,0.80f);

Map<String,String> map4 = new HashMap<>(map1);

자바 HashMap 메소드

자바에서 HashMap의 중요한 메소드를 살펴보자.

  1. public void clear(): 이 HashMap 메서드는 모든 매핑을 제거하고 HashMap은 비어 있게 됩니다.
  2. public boolean containsKey(객체 키): 이 메서드는 키가 존재하면 'true'를 반환하고 그렇지 않으면 'false'를 반환합니다.
  3. public boolean containsValue(Object value): 이 HashMap 메서드는 값이 존재하면 true를 반환하고 그렇지 않으면 false를 반환합니다.
  4. public Set> entrySet(): 이 메서드는 HashMap 매핑의 Set 보기를 반환합니다. 이 세트는 지도에 의해 지원되므로 지도에 대한 변경 사항이 세트에 반영되고 그 반대도 마찬가지입니다.
  5. public V get(객체 키): 지정된 키에 매핑된 값을 반환하거나 해당 키에 대한 매핑이 없으면 null을 반환합니다.
  6. public boolean isEmpty(): 키-값 매핑이 없는 경우 true를 반환하는 유틸리티 메서드입니다.
  7. public Set keySet(): 이 맵에 포함된 키의 Set 뷰를 반환합니다. 세트는 지도에 의해 지원되므로 지도에 대한 변경 사항은 세트에 반영되며 그 반대도 마찬가지입니다.
  8. public V put(K key, V value): 지정된 값을 이 맵의 지정된 키와 연결합니다. 맵에 이전에 키에 대한 매핑이 포함된 경우 이전 값이 대체됩니다.
  9. public void putAll(Map m): 지정된 지도에서 이 지도로 모든 매핑을 복사합니다. 이러한 매핑은 현재 지정된 맵에 있는 키에 대해 이 맵이 가지고 있던 모든 매핑을 대체합니다.
  10. public V remove(객체 키): 이 맵이 있는 경우 지정된 키에 대한 매핑을 제거합니다.
  11. public int size(): 이 맵의 키-값 매핑 수를 반환합니다.
  12. public Collection values(): 이 맵에 포함된 값의 Collection 보기를 반환합니다. 컬렉션은 지도에 의해 지원되므로 지도에 대한 변경 사항은 컬렉션에 반영되며 반대의 경우도 마찬가지입니다.

Java 8에 도입된 HashMap에는 많은 새로운 메서드가 있습니다.

  1. public V computeIfAbsent(K key, Function mappingFunction): 지정된 키가 아직 값과 연결되지 않은 경우(또는 null에 매핑된 경우) 이 메서드는 다음을 사용하여 값을 계산하려고 시도합니다. Null이 아니면 주어진 매핑 함수를 HashMap에 입력합니다.
  2. public V computeIfPresent(K key, BiFunction remappingFunction): 지정된 키에 대한 값이 존재하고 null이 아닌 경우 키가 지정된 새 매핑을 계산하려고 시도합니다. 및 현재 매핑된 값입니다.
  3. public V compute(K key, BiFunction remappingFunction): 이 HashMap 메서드는 지정된 키와 현재 매핑된 값에 대한 매핑을 계산하려고 시도합니다.
  4. public void forEach(BiConsumer action): 이 메서드는 이 맵의 각 항목에 대해 지정된 작업을 수행합니다.
  5. public V getOrDefault(Object key, V defaultValue): 지정된 키에 대한 매핑이 발견되지 않으면 defaultValue가 반환된다는 점을 제외하면 get과 동일합니다.
  6. public V merge(K key, V value, BiFunction remappingFunction): 지정된 키가 아직 값과 연결되지 않았거나 null과 연결되어 있으면 해당 키를 다음과 연결합니다. 주어진 null이 아닌 값. 그렇지 않으면 연결된 값을 지정된 리매핑 함수의 결과로 바꾸거나 결과가 null인 경우 제거합니다.
  7. public V putIfAbsent(K key, V value): 지정된 키가 아직 값과 연결되지 않은 경우(또는 null에 매핑된 경우) 지정된 값과 연결하고 null을 반환하고 그렇지 않으면 현재 값을 반환합니다.
  8. public boolean remove(Object key, Object value): 현재 지정된 값에 매핑된 경우에만 지정된 키에 대한 항목을 제거합니다.
  9. public boolean replace(K key, V oldValue, V newValue): 현재 지정된 값에 매핑된 경우에만 지정된 키에 대한 항목을 바꿉니다.
  10. public V replace(K key, V value): 현재 어떤 값에 매핑되어 있는 경우에만 지정된 키에 대한 항목을 바꿉니다.
  11. public void replaceAll(BiFunction function): 각 항목의 값을 해당 항목에 지정된 함수를 호출한 결과로 바꿉니다.

자바 HashMap 예제

다음은 일반적으로 사용되는 HashMap에 대한 간단한 Java 프로그램입니다.

package com.journaldev.examples;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class HashMapExample {

	public static void main(String[] args) {

		Map<String, String> map = new HashMap<>();

		map.put("1", "1"); // put example
		map.put("2", "2");
		map.put("3", "3");
		map.put("4", null); // null value
		map.put(null, "100"); // null key

		String value = map.get("3"); // get example
		System.out.println("Key = 3, Value = " + value);

		value = map.getOrDefault("5", "Default Value");
		System.out.println("Key = 5, Value=" + value);

		boolean keyExists = map.containsKey(null);
		boolean valueExists = map.containsValue("100");

		System.out.println("keyExists=" + keyExists + ", valueExists=" + valueExists);

		Set<Entry<String, String>> entrySet = map.entrySet();
		System.out.println(entrySet);

		System.out.println("map size=" + map.size());

		Map<String, String> map1 = new HashMap<>();
		map1.putAll(map);
		System.out.println("map1 mappings= " + map1);

		String nullKeyValue = map1.remove(null);
		System.out.println("map1 null key value = " + nullKeyValue);
		System.out.println("map1 after removing null key = " + map1);

		Set<String> keySet = map.keySet();
		System.out.println("map keys = " + keySet);

		Collection<String> values = map.values();
		System.out.println("map values = " + values);

		map.clear();
		System.out.println("map is empty=" + map.isEmpty());

	}

}

아래는 위의 Java HashMap 예제 프로그램의 출력입니다.

Key = 3, Value = 3
Key = 5, Value=Default Value
keyExists=true, valueExists=true
[null=100, 1=1, 2=2, 3=3, 4=null]
map size=5
map1 mappings= {null=100, 1=1, 2=2, 3=3, 4=null}
map1 null key value = 100
map1 after removing null key = {1=1, 2=2, 3=3, 4=null}
map keys = [null, 1, 2, 3, 4]
map values = [100, 1, 2, 3, null]
map is empty=true

HashMap은 Java에서 어떻게 작동합니까?

자바 HashMap 로드 팩터

Load Factor는 HashMap이 다시 해시되고 버킷 크기가 증가하는 시기를 파악하는 데 사용됩니다. 버킷 또는 용량의 기본값은 16이고 부하 계수는 0.75입니다. 재해싱 임계값은 용량과 부하 계수를 곱하여 계산됩니다. 따라서 기본 임계값은 12입니다. 따라서 HashMap에 12개 이상의 매핑이 있는 경우 다시 해시되고 빈 수가 2의 거듭제곱, 즉 32로 증가합니다. HashMap 용량은 항상 2의 거듭제곱입니다. 기본 로드 0.75의 계수는 공간과 시간 복잡도 사이에 적절한 절충안을 제공합니다. 그러나 요구 사항에 따라 다른 값으로 설정할 수 있습니다. 공간을 절약하려면 값을 0.80 또는 0.90으로 늘릴 수 있지만 가져오기/넣기 작업에 더 많은 시간이 걸립니다.

Java HashMap 키 세트

Java HashMap keySet 메서드는 HashMap에 있는 키의 Set 보기를 반환합니다. 이 Set 보기는 HashMap에 의해 지원되며 HashMap의 모든 변경 사항은 Set에 반영되며 그 반대의 경우도 마찬가지입니다. 아래는 HashMap keySet 예제를 보여주는 간단한 프로그램과 맵이 지원하지 않는 keySet을 원하는 경우 갈 수 있는 방법입니다.

package com.journaldev.examples;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class HashMapKeySetExample {

	public static void main(String[] args) {

		Map<String, String> map = new HashMap<>();
		map.put("1", "1");
		map.put("2", "2");
		map.put("3", "3");

		Set<String> keySet = map.keySet();
		System.out.println(keySet);

		map.put("4", "4");
		System.out.println(keySet); // keySet is backed by Map

		keySet.remove("1");
		System.out.println(map); // map is also modified

		keySet = new HashSet<>(map.keySet()); // copies the key to new Set
		map.put("5", "5");
		System.out.println(keySet); // keySet is not modified
	}

}

위 프로그램의 출력은 keySet이 지도에 의해 뒷받침된다는 것을 분명히 할 것입니다.

[1, 2, 3]
[1, 2, 3, 4]
{2=2, 3=3, 4=4}
[2, 3, 4]

자바 HashMap 값

Java HashMap 값 메소드는 맵에 있는 값의 콜렉션 보기를 리턴합니다. 이 컬렉션은 HashMap에 의해 지원되므로 HashMap의 모든 변경 사항은 값 컬렉션에 반영되며 그 반대도 마찬가지입니다. 아래의 간단한 예는 HashMap 값 수집의 이러한 동작을 확인합니다.

package com.journaldev.examples;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class HashMapValuesExample {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("1", "1");
		map.put("2", "2");
		map.put("3", null);
		map.put("4", null);
		map.put(null, "100");

		Collection<String> values = map.values();
		System.out.println("map values = " + values);

		map.remove(null);
		System.out.println("map values after removing null key = " + values);

		map.put("5", "5");
		System.out.println("map values after put = " + values);

		System.out.println(map);
		values.remove("1"); // changing values collection
		System.out.println(map); // updates in map too

	}

}

위 프로그램의 출력은 아래와 같습니다.

map values = [100, 1, 2, null, null]
map values after removing null key = [1, 2, null, null]
map values after put = [1, 2, null, null, 5]
{1=1, 2=2, 3=null, 4=null, 5=5}
{2=2, 3=null, 4=null, 5=5}

자바 HashMap entrySet

Java HashMap entrySet 메소드는 맵핑의 세트 보기를 리턴합니다. 이 entrySet는 HashMap에 의해 지원되므로 맵의 모든 변경 사항은 항목 집합에 반영되며 그 반대도 마찬가지입니다. HashMap entrySet 예제에 대한 아래 예제 프로그램을 살펴보십시오.

package com.journaldev.examples;

import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class HashMapEntrySetExample {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("1", "1");
		map.put("2", null);
		map.put(null, "100");

		Set<Entry<String,String>> entrySet = map.entrySet();
		Iterator<Entry<String, String>> iterator = entrySet.iterator();
		Entry<String, String> next = null;
		
		System.out.println("map before processing = "+map);
		System.out.println("entrySet before processing = "+entrySet);
		while(iterator.hasNext()){
			next = iterator.next();
			System.out.println("Processing on: "+next.getValue());
			if(next.getKey() == null) iterator.remove();
		}
		
		System.out.println("map after processing = "+map);
		System.out.println("entrySet after processing = "+entrySet);
		
		Entry<String, String> simpleEntry = new AbstractMap.SimpleEntry<String, String>("1","1");
		entrySet.remove(simpleEntry);
		System.out.println("map after removing Entry = "+map);
		System.out.println("entrySet after removing Entry = "+entrySet);
	}

}

아래는 위의 프로그램에 의해 생성된 출력입니다.

map before processing = {null=100, 1=1, 2=null}
entrySet before processing = [null=100, 1=1, 2=null]
Processing on: 100
Processing on: 1
Processing on: null
map after processing = {1=1, 2=null}
entrySet after processing = [1=1, 2=null]
map after removing Entry = {2=null}
entrySet after removing Entry = [2=null]

Java HashMap putIfAbsent

Java 8에 도입된 HashMap putIfAbsent 메서드의 간단한 예입니다.

package com.journaldev.examples;

import java.util.HashMap;
import java.util.Map;

public class HashMapPutIfAbsentExample {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("1", "1");
		map.put("2", null);
		map.put(null, "100");

		System.out.println("map before putIfAbsent = "+map);
		String value = map.putIfAbsent("1", "4");
		System.out.println("map after putIfAbsent = "+map);
		System.out.println("putIfAbsent returns: "+value);
		
		System.out.println("map before putIfAbsent = "+map);
		value = map.putIfAbsent("3", "3");
		System.out.println("map after putIfAbsent = "+map);
		System.out.println("putIfAbsent returns: "+value);
	}

}

위 프로그램의 출력은 다음과 같습니다.

map before putIfAbsent = {null=100, 1=1, 2=null}
map after putIfAbsent = {null=100, 1=1, 2=null}
putIfAbsent returns: 1
map before putIfAbsent = {null=100, 1=1, 2=null}
map after putIfAbsent = {null=100, 1=1, 2=null, 3=3}
putIfAbsent returns: null

각각에 대한 Java HashMap

HashMap forEach 메서드는 Java 8에서 도입되었습니다. 모든 항목이 처리되거나 작업에서 예외가 발생할 때까지 맵의 각 항목에 대해 지정된 작업을 수행하는 매우 유용한 메서드입니다.

package com.journaldev.examples;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

public class HashMapForEachExample {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("1", "1");
		map.put("2", null);
		map.put(null, "100");

		BiConsumer<String, String> action = new MyBiConsumer();
		map.forEach(action);
		
		//lambda expression example
		System.out.println("\nHashMap forEach lambda example\n");
		map.forEach((k,v) -> {System.out.println("Key = "+k+", Value = "+v);});
	}

}

class MyBiConsumer implements BiConsumer<String, String> {

	@Override
	public void accept(String t, String u) {
		System.out.println("Key = " + t);
		System.out.println("Processing on value = " + u);
	}

}

위의 HashMap forEach 예제 프로그램의 출력은 다음과 같습니다.

Key = null
Processing on value = 100
Key = 1
Processing on value = 1
Key = 2
Processing on value = null

HashMap forEach lambda example

Key = null, Value = 100
Key = 1, Value = 1
Key = 2, Value = null

Java HashMap replaceAll

HashMap replaceAll 메소드를 사용하여 각 항목의 값을 해당 항목에서 주어진 함수를 호출한 결과로 바꿀 수 있습니다. 이 메서드는 Java 8에 추가되었으며 이 메서드 인수에 대해 람다 식을 사용할 수 있습니다.

package com.journaldev.examples;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;

public class HashMapReplaceAllExample {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("1", "1");
		map.put("2", "2");
		map.put(null, "100");

		System.out.println("map before replaceAll = " + map);
		BiFunction<String, String, String> function = new MyBiFunction();
		map.replaceAll(function);
		System.out.println("map after replaceAll = " + map);

		// replaceAll using lambda expressions
		map.replaceAll((k, v) -> {
			if (k != null) return k + v;
			else return v;});
		System.out.println("map after replaceAll lambda expression = " + map);

	}

}

class MyBiFunction implements BiFunction<String, String, String> {

	@Override
	public String apply(String t, String u) {
		if (t != null)
			return t + u;
		else
			return u;
	}

}

위의 HashMap replaceAll 프로그램의 출력은 다음과 같습니다.

map before replaceAll = {null=100, 1=1, 2=2}
map after replaceAll = {null=100, 1=11, 2=22}
map after replaceAll lambda example = {null=100, 1=111, 2=222}

Java HashMap computeIfAbsent

HashMap computeIfAbsent 메서드는 키가 맵에 없는 경우에만 값을 계산합니다. 값을 계산한 후 null이 아니면 맵에 넣습니다.

package com.journaldev.examples;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public class HashMapComputeIfAbsent {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("1", "10");
		map.put("2", "20");
		map.put(null, "100");

		Function<String, String> function = new MyFunction();
		map.computeIfAbsent("3", function); //key not present
		map.computeIfAbsent("2", function); //key already present
		
		//lambda way
		map.computeIfAbsent("4", v -> {return v;});
		map.computeIfAbsent("5", v -> {return null;}); //null value won't get inserted
		System.out.println(map);
	}

}

class MyFunction implements Function<String, String> {

	@Override
	public String apply(String t) {
		return t;
	}
	
}

위 프로그램의 출력은 다음과 같습니다.

{null=100, 1=10, 2=20, 3=3, 4=4}

Java HashMap computeIfPresent

Java HashMap computeIfPresent 메서드는 지정된 키가 있고 값이 null이 아닌 경우 값을 다시 계산합니다. 함수가 null을 반환하면 매핑이 제거됩니다.

package com.journaldev.examples;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;

public class HashMapComputeIfPresentExample {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("1", "10");
		map.put("2", "20");
		map.put(null, "100");
		map.put("10", null);

		System.out.println("map before computeIfPresent = " + map);
		BiFunction<String, String, String> function = new MyBiFunction1();
		for (String key : map.keySet()) {
			map.computeIfPresent(key, function);
		}
		
		System.out.println("map after computeIfPresent = " + map);
		map.computeIfPresent("1", (k,v) -> {return null;}); // mapping will be removed
		System.out.println("map after computeIfPresent = " + map);

	}

}

class MyBiFunction1 implements BiFunction<String, String, String> {

	@Override
	public String apply(String t, String u) {
		return t + u;
	}

}

HashMap computeIfPresent 예제에서 생성된 출력은 다음과 같습니다.

map before computeIfPresent = {null=100, 1=10, 2=20, 10=null}
map after computeIfPresent = {null=null100, 1=110, 2=220, 10=null}
map after computeIfPresent = {null=null100, 2=220, 10=null}

자바 HashMap 컴퓨팅

키와 값을 기반으로 모든 매핑에 함수를 적용하려면 compute 메서드를 사용해야 합니다. 매핑이 없고 이 방법을 사용하면 컴퓨팅 함수에 대해 값이 null이 됩니다.

package com.journaldev.examples;

import java.util.HashMap;
import java.util.Map;

public class HashMapComputeExample {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("1", "1");
		map.put("2", "2");
		map.put(null, "10");
		map.put("10", null);

		System.out.println("map before compute = "+map);
		for (String key : map.keySet()) {
			map.compute(key, (k,v) -> {return k+v;});
		}
		map.compute("5", (k,v) -> {return k+v;}); //key not present, v = null
		System.out.println("map after compute = "+map);
	}

}

HashMap 컴퓨팅 예제의 출력은 다음과 같습니다.

map before compute = {null=10, 1=1, 2=2, 10=null}
map after compute = {null=null10, 1=11, 2=22, 5=5null, 10=10null}

자바 HashMap 병합

지정된 키가 없거나 null과 연결된 경우 지정된 null이 아닌 값과 연결합니다. 그렇지 않으면 연결된 값을 지정된 리매핑 함수의 결과로 바꾸거나 결과가 null인 경우 제거합니다.

package com.journaldev.examples;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

public class HashMapMergeExample {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>();
		map.put("1", "1");
		map.put("2", "2");
		map.put(null, "10");
		map.put("10", null);

		for (Entry<String, String> entry : map.entrySet()) {
			String key = entry.getKey();
			String value = entry.getValue();
			//merge throws NullPointerException if key or value is null
			if(key != null && value != null) 
			map.merge(entry.getKey(), entry.getValue(), 
					(k, v) -> {return k + v;});
		}
		System.out.println(map);
		
		map.merge("5", "5", (k, v) -> {return k + v;}); // key not present
		System.out.println(map);
		
		map.merge("1", "1", (k, v) -> {return null;}); // method return null, so remove
		System.out.println(map);

	}

}

위 프로그램의 출력은 다음과 같습니다.

{null=10, 1=11, 2=22, 10=null}
{null=10, 1=11, 2=22, 5=5, 10=null}
{null=10, 2=22, 5=5, 10=null}

이것이 Java의 HashMap에 대한 전부입니다. 중요한 것이 누락되지 않기를 바랍니다. 당신이 그것을 좋아한다면 너무 다른 사람들과 공유하십시오. 참조: API 문서