Поиск по сайту:

Java HashMap — HashMap в Java


Java HashMap — один из самых популярных классов Collection в java. Java HashMap - это реализация на основе хеш-таблицы. HashMap в java расширяет класс AbstractMap, реализующий интерфейс Map.

Java HashMap

  1. Java HashMap допускает нулевой ключ и нулевые значения.
  2. HashMap не является упорядоченной коллекцией. Вы можете перебирать записи HashMap с помощью набора ключей, но не гарантируется, что они будут в порядке их добавления в HashMap.
  3. HashMap почти аналогичен 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. Этот конструктор создаст пустой HashMap с начальной емкостью по умолчанию 16 и коэффициентом загрузки 0,75.
  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);

Методы хэш-карты Java

Давайте посмотрим на важные методы HashMap в java.

  1. public void clear(): этот метод HashMap удалит все сопоставления, и HashMap станет пустым.
  2. public boolean containsKey(Object key): этот метод возвращает значение «истина», если ключ существует, в противном случае он возвращает значение «ложь».
  3. public boolean containsValue(значение объекта): этот метод HashMap возвращает значение true, если значение существует, в противном случае false.
  4. public Set> entrySet(): этот метод возвращает представление Set сопоставлений HashMap. Этот набор поддерживается картой, поэтому изменения в карте отражаются в наборе и наоборот.
  5. public V get(Object key): возвращает значение, сопоставленное с указанным ключом, или null, если сопоставление для ключа отсутствует.
  6. public boolean isEmpty(): служебный метод, возвращающий true, если сопоставления ключ-значение отсутствуют.
  7. public Set keySet(): возвращает набор ключей, содержащихся в этой карте. Набор поддерживается картой, поэтому изменения в карте отражаются в наборе и наоборот.
  8. public V put(K key, V value): связывает указанное значение с указанным ключом на этой карте. Если карта ранее содержала сопоставление для ключа, старое значение заменяется.
  9. public void putAll(Map m): Копирует все сопоставления с указанной карты на эту карту. Эти сопоставления заменят любые сопоставления, которые эта карта имела для любого из ключей, находящихся в настоящее время в указанной карте.
  10. public V remove(Object key): удаляет сопоставление указанного ключа с этой сопоставления, если оно присутствует.
  11. public int size(): возвращает количество сопоставлений ключ-значение в этой карте.
  12. public Collection values(): возвращает представление коллекции значений, содержащихся в этой карте. Коллекция поддерживается картой, поэтому изменения в карте отражаются в коллекции и наоборот.

В Java 8 появилось много новых методов HashMap.

  1. public V calculateIfAbsent(K key, Function mappingFunction): если указанный ключ еще не связан со значением (или сопоставлен с нулевым значением), этот метод пытается вычислить его значение, используя заданную функцию сопоставления и вводит ее в HashMap, если только это не Null.
  2. public V calculateIfPresent(K key, BiFunction remappingFunction): если значение для указанного ключа присутствует и не равно нулю, пытается вычислить новое сопоставление с учетом ключа и его текущее сопоставленное значение.
  3. public V calculate(K key, BiFunction remappingFunction): этот метод HashMap пытается вычислить сопоставление для указанного ключа и его текущего сопоставленного значения.
  4. public void forEach(BiConsumer action): этот метод выполняет заданное действие для каждой записи на этой карте.
  5. public V getOrDefault(Object key, V defaultValue): То же, что и get, за исключением того, что возвращается defaultValue, если сопоставление для указанного ключа не найдено.
  6. public V merge(K key, V value, BiFunction remappingFunction): если указанный ключ еще не связан со значением или связан с нулем, связывает его с заданное ненулевое значение. В противном случае заменяет связанное значение результатами данной функции переназначения или удаляет, если результат равен нулю.
  7. public V putIfAbsent(K key, V value): если указанный ключ еще не связан со значением (или сопоставляется с нулевым значением), связывает его с заданным значением и возвращает ноль, иначе возвращает текущее значение.
  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): заменяет значение каждой записи результатом вызова данной функции для этой записи.

Пример хэш-карты Java

Вот простая java-программа для часто используемых методов HashMap.

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?

Коэффициент загрузки Java HashMap

Коэффициент загрузки используется, чтобы выяснить, когда HashMap будет перехэширован и размер корзины будет увеличен. Значение по умолчанию для ковша или емкости — 16, а коэффициент загрузки — 0,75. Порог для повторного хеширования рассчитывается путем умножения емкости и коэффициента загрузки. Таким образом, пороговое значение по умолчанию будет равно 12. Поэтому, когда HashMap будет иметь более 12 сопоставлений, оно будет перехэшировано, а количество бинов будет увеличено до следующей степени 2, т.е. 32. Обратите внимание, что емкость HashMap всегда равна степени 2. Загрузка по умолчанию Коэффициент 0,75 обеспечивает хороший компромисс между пространственной и временной сложностью. Но вы можете установить для него разные значения в зависимости от ваших требований. Если вы хотите сэкономить место, вы можете увеличить его значение до 0,80 или 0,90, но тогда операции получения/установки займут больше времени.

Набор ключей Java HashMap

Метод keySet Java HashMap возвращает набор ключей в HashMap. Это представление Set поддерживается HashMap, и любые изменения в HashMap отражаются в Set и наоборот. Ниже приведена простая программа, демонстрирующая примеры набора ключей HashMap и способы, которые следует предпринять, если вы хотите, чтобы набор ключей не поддерживался картой.

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]

Значения Java 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}

Набор записей Java HashMap

Метод entrySet Java HashMap возвращает представление сопоставлений Set. Этот набор записей поддерживается 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

Простой пример метода putIfAbsent HashMap, представленного в Java 8.

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 для каждой примерной программы:

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 можно использовать для замены значения каждой записи результатом вызова данной функции для этой записи. Этот метод добавлен в 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 вычислить, если отсутствует

Метод HashMap calculateIfAbsent вычисляет значение, только если ключ отсутствует на карте. После вычисления значения оно помещается на карту, если оно не равно нулю.

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 calculateIfPresent повторно вычисляет значение, если указанный ключ присутствует и значение не равно нулю. Если функция возвращает значение 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 calculateIfPresent:

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}

Вычисление Java HashMap

Если вы хотите применить функцию ко всем сопоставлениям на основе ее ключа и значения, следует использовать метод вычисления. Если нет сопоставления и используется этот метод, значение для функции вычисления будет нулевым.

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}

Слияние Java HashMap

Если указанный ключ отсутствует или связан с нулевым значением, то связывает его с заданным ненулевым значением. В противном случае заменяет связанное значение результатами данной функции переназначения или удаляет, если результат равен нулю.

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}

На этом по HashMap на Java все, надеюсь ничего важного не упущено. Поделитесь им с другими, если вам понравилось. Ссылка: документ API