Java HashMap - Java의 HashMap
Java HashMap은 Java에서 가장 인기 있는 Collection 클래스 중 하나입니다. Java HashMap은 해시 테이블 기반 구현입니다. Java의 HashMap은 Map 인터페이스를 구현하는 AbstractMap 클래스를 확장합니다.
자바 해시맵
- Java HashMap은 null 키와 null 값을 허용합니다.
- HashMap은 정렬된 컬렉션이 아닙니다. 키 세트를 통해 HashMap 항목을 반복할 수 있지만 HashMap에 추가된 순서가 보장되지는 않습니다.
- HashMap은 동기화되지 않고 null 키와 값을 허용한다는 점을 제외하면 Hashtable과 거의 유사합니다.
- HashMap은 지도 항목을 저장하기 위해 내부 클래스인 Node
를 사용합니다. - HashMap은 항목을 버킷 또는 빈이라는 여러 단일 연결 목록에 저장합니다. 빈의 기본 수는 16이며 항상 2의 거듭제곱입니다.
- HashMap은 가져오기 및 넣기 작업을 위해 키에 hashCode() 및 equals() 메서드를 사용합니다. 따라서 HashMap 키 개체는 이러한 메서드의 좋은 구현을 제공해야 합니다. 이것이 String 및 Interger와 같은 불변 클래스가 키에 더 적합한 이유입니다.
- Java HashMap은 스레드로부터 안전하지 않습니다. 다중 스레드 환경의 경우 ConcurrentHashMap 클래스를 사용하거나
Collections.synchronizedMap()
메서드를 사용하여 동기화된 맵을 가져와야 합니다.
Java HashMap 생성자
Java HashMap은 네 개의 생성자를 제공합니다.
- public HashMap(): 가장 일반적으로 사용되는 HashMap 생성자. 이 생성자는 기본 초기 용량이 16이고 부하율이 0.75인 빈 HashMap을 생성합니다.
- public HashMap(int initialCapacity): 이 HashMap 생성자는 초기 용량과 0.75 로드 팩터를 지정하는 데 사용됩니다. 이는 HashMap에 저장할 매핑 수를 알고 있는 경우 재해싱을 방지하는 데 유용합니다.
- public HashMap(int initialCapacity, float loadFactor): 이 HashMap 생성자는 지정된 초기 용량 및 로드 팩터를 사용하여 빈 HashMap을 생성합니다. HashMap에 저장할 최대 매핑 수를 알고 있는 경우 이를 사용할 수 있습니다. 일반적인 시나리오에서는 부하 계수 0.75가 공간과 시간 비용 사이에 적절한 절충안을 제공하기 때문에 이를 피해야 합니다.
- public HashMap(Map extends K, ? extends V> 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의 중요한 메소드를 살펴보자.
- public void clear(): 이 HashMap 메서드는 모든 매핑을 제거하고 HashMap은 비어 있게 됩니다.
- public boolean containsKey(객체 키): 이 메서드는 키가 존재하면 'true'를 반환하고 그렇지 않으면 'false'를 반환합니다.
- public boolean containsValue(Object value): 이 HashMap 메서드는 값이 존재하면 true를 반환하고 그렇지 않으면 false를 반환합니다.
- public Set
> entrySet(): 이 메서드는 HashMap 매핑의 Set 보기를 반환합니다. 이 세트는 지도에 의해 지원되므로 지도에 대한 변경 사항이 세트에 반영되고 그 반대도 마찬가지입니다. - public V get(객체 키): 지정된 키에 매핑된 값을 반환하거나 해당 키에 대한 매핑이 없으면 null을 반환합니다.
- public boolean isEmpty(): 키-값 매핑이 없는 경우 true를 반환하는 유틸리티 메서드입니다.
- public Set
keySet(): 이 맵에 포함된 키의 Set 뷰를 반환합니다. 세트는 지도에 의해 지원되므로 지도에 대한 변경 사항은 세트에 반영되며 그 반대도 마찬가지입니다. - public V put(K key, V value): 지정된 값을 이 맵의 지정된 키와 연결합니다. 맵에 이전에 키에 대한 매핑이 포함된 경우 이전 값이 대체됩니다.
- public void putAll(Map extends K, ? extends V> m): 지정된 지도에서 이 지도로 모든 매핑을 복사합니다. 이러한 매핑은 현재 지정된 맵에 있는 키에 대해 이 맵이 가지고 있던 모든 매핑을 대체합니다.
- public V remove(객체 키): 이 맵이 있는 경우 지정된 키에 대한 매핑을 제거합니다.
- public int size(): 이 맵의 키-값 매핑 수를 반환합니다.
- public Collection
values(): 이 맵에 포함된 값의 Collection 보기를 반환합니다. 컬렉션은 지도에 의해 지원되므로 지도에 대한 변경 사항은 컬렉션에 반영되며 반대의 경우도 마찬가지입니다.
Java 8에 도입된 HashMap에는 많은 새로운 메서드가 있습니다.
- public V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction): 지정된 키가 아직 값과 연결되지 않은 경우(또는 null에 매핑된 경우) 이 메서드는 다음을 사용하여 값을 계산하려고 시도합니다. Null이 아니면 주어진 매핑 함수를 HashMap에 입력합니다.
- public V computeIfPresent(K key, BiFunction super K, ? super V, ? extends V> remappingFunction): 지정된 키에 대한 값이 존재하고 null이 아닌 경우 키가 지정된 새 매핑을 계산하려고 시도합니다. 및 현재 매핑된 값입니다.
- public V compute(K key, BiFunction super K, ? super V, ? extends V> remappingFunction): 이 HashMap 메서드는 지정된 키와 현재 매핑된 값에 대한 매핑을 계산하려고 시도합니다.
- public void forEach(BiConsumer super K, ? super V> action): 이 메서드는 이 맵의 각 항목에 대해 지정된 작업을 수행합니다.
- public V getOrDefault(Object key, V defaultValue): 지정된 키에 대한 매핑이 발견되지 않으면 defaultValue가 반환된다는 점을 제외하면 get과 동일합니다.
- public V merge(K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction): 지정된 키가 아직 값과 연결되지 않았거나 null과 연결되어 있으면 해당 키를 다음과 연결합니다. 주어진 null이 아닌 값. 그렇지 않으면 연결된 값을 지정된 리매핑 함수의 결과로 바꾸거나 결과가 null인 경우 제거합니다.
- public V putIfAbsent(K key, V value): 지정된 키가 아직 값과 연결되지 않은 경우(또는 null에 매핑된 경우) 지정된 값과 연결하고 null을 반환하고 그렇지 않으면 현재 값을 반환합니다. 리>
- public boolean remove(Object key, Object value): 현재 지정된 값에 매핑된 경우에만 지정된 키에 대한 항목을 제거합니다.
- public boolean replace(K key, V oldValue, V newValue): 현재 지정된 값에 매핑된 경우에만 지정된 키에 대한 항목을 바꿉니다.
- public V replace(K key, V value): 현재 어떤 값에 매핑되어 있는 경우에만 지정된 키에 대한 항목을 바꿉니다.
- public void replaceAll(BiFunction super K, ? super V, ? extends V> 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 문서