第四章 java中的HashMap


Java 集合 API 提供了许多内置的类和接口来处理对象集合。学习和掌握 Java 集合概念非常重要。它是核心 java 教程中非常重要的一部分。

HashMap 是基于哈希表的Map 接口实现。它将条目存储在键值对中。它将键映射到值。它是最常用的Collection之一。

Java HashMap

  1. HashMap实现Map一个将键映射到值的接口。
  2. 它不是同步的,也不是线程安全的。
  3. 不允许重复键
  4. 允许一null键多值null
  5. 它是无序的集合,不保证元素的任何特定顺序。

哈希映射

您是否注意到 HashMap 实现了 Map 接口,即使 AbstractMap 已经实现了它? 是的,只是为了让事情更明显,HashMap再次实现了Map接口,再次实现接口并没有错。你不必通过类Hierarchy发现HashMap实现了Map接口。

HashMap 构造函数

Java HashMap 类有四个构造函数 public HashMap():这是默认构造函数,主要使用。它创建一个空的 HashMap,默认初始容量为 16,加载因子为 0.75。 public HashMap(int initialCapacity):该构造函数用于指定HashMap的初始容量,默认加载因子0.75。 public HashMap(int initialCapacity,float loadFactor):该构造函数用于指定HashMap的初始容量和加载因子。在大多数情况下,您应该避免使用此构造函数,除非您确定这一点,因为负载因子 0.75 提供了时间和空间之间的良好折衷。 public HashMap(Map<? extends K,? extends V> m):当您想从其他 Map(例如TreeMap或[LinkedHashMap)创建 HashMap 时,使用此构造函数。

将键值对添加到 HashMap

我们可以使用put()方法将条目添加到HashMap. 例子:

package org.arpit.java2blog;
package org.arpit.java2blog;
import java.util.HashMap;

public class HashMapBuiltMain {

    public static void main(String[] args) {
        HashMap<Integer, String> employeeHashmap = new HashMap<Integer, String>();
        // Putting key-values pairs in HashMap
        employeeHashmap.put(1, "Arpit");
        employeeHashmap.put(2, "John");
        employeeHashmap.put(3, "Martin");
        employeeHashmap.put(4, "Vaibhav");

        System.out.println(employeeHashmap);
    }
}

当你运行上面的程序时,你会得到下面的输出

{1=Arpit, 2=John, 3=Martin, 4=Vaibhav}

如果您只想在 HashMap 中不存在条目时才添加条目怎么办? 您可以putIfAbsent()在这种情况下使用该方法。

从 HashMap 中删除条目

有两种方法可以删除 HashMap 中的条目。

  1. remove(Object key):它从 HashMap 中删除键
  2. remove(Object key,Object value):如果值与传递的参数值相同,则删除键。
package org.arpit.java2blog.HashMap;

import java.util.HashMap;

public class HashMapRemoveMain {

    public static void main(String[] args) {
        HashMap<String, Integer> vehicleMaxSpeedMap = new HashMap<String, Integer>();
        // Putting key-values pairs in HashMap

        vehicleMaxSpeedMap.put("Bike", 120);
        vehicleMaxSpeedMap.put("Car", 220);
        vehicleMaxSpeedMap.put("Truck", 160);
        vehicleMaxSpeedMap.put("Activa", 140);
        System.out.println(vehicleMaxSpeedMap);

        // Remove truck key
        Integer speed = vehicleMaxSpeedMap.remove("Truck");
        System.out.println("===============================");
        System.out.println("Vehicle Truck with max speed "+speed+" removed from HashMap");
        System.out.println(vehicleMaxSpeedMap);
        System.out.println("================================");

        // Remove Car if value is 200
        boolean isCarRemoved = vehicleMaxSpeedMap.remove("Car",200);
        // Car key won't be removed as associated value is 220
        System.out.println("Did car removed from HashMap: "+isCarRemoved);
        System.out.println(vehicleMaxSpeedMap);
        System.out.println("===============================");

        // Remove Car if value is 200
        boolean isActivaRemoved = vehicleMaxSpeedMap.remove("Activa",140);
        // Activa key will be removed as associated value is 140
        System.out.println("Did activa removed from HashMap: "+isActivaRemoved);
        System.out.println(vehicleMaxSpeedMap);
        System.out.println("===============================");

    }
}

输出:

{Car=220, Activa=140, Truck=160, Bike=120}
===============================
Vehicle Truck with max speed 160 removed from HashMap
{Car=220, Activa=140, Bike=120}
================================
Did car removed from HashMap: false
{Car=220, Activa=140, Bike=120}
===============================
Did activa removed from HashMap: true
{Car=220, Bike=120}
===============================

重要的 HashMap 方法

get():从 HashMap 中检索值 put():将值放入 HashMap isEmpty:检查 HashMap 是否为空。 containsKey():检查存在的键是否为 HashMap containsValue():检查 HashMap 中是否存在值:检查 HashMap size()的大小 clear():从 Hashmap 中删除所有元素 clone():它创建 HashMap 的浅表副本。

这是一个涵盖这些方法的示例。

package org.arpit.java2blog.HashMap;

import java.util.HashMap;

public class HashMapMethodsMain {

    public static void main(String[] args) {
        HashMap<String, String> employeeDeptmap = new HashMap<>();

        //check if map is empty
        boolean empty = employeeDeptmap.isEmpty();
        System.out.println("is employeeDeptmap empty: "+empty);

        // Putting key-values pairs in HashMap
        employeeDeptmap.put("Arpit","Tech");
        employeeDeptmap.put("John", "Sales");
        employeeDeptmap.put("Martin", "HR");
        employeeDeptmap.put("Vaibhav","Tech");

      System.out.println(employeeDeptmap);
        //check size of map
        System.out.println("size of employeeDeptmap: "+employeeDeptmap.size());

        // get value from HashMap
        System.out.println("Martin's department: "+employeeDeptmap.get("Martin"));
        // Robin's department will be null as we don't have key as "Robin"
        System.out.println("Robin's department: "+employeeDeptmap.get("Robin"));

        if(employeeDeptmap.containsKey("John"))
        {
            System.out.println("employeeDeptmap has John as key");
        }

        if(employeeDeptmap.containsValue("Sales"))
        {
            System.out.println("employeeDeptmap has Sales as value");
        }

        // Removing all entries from Map
        employeeDeptmap.clear();
        System.out.println(employeeDeptmap);
    }
}

输出:

is employeeDeptmap empty: true
{Arpit=Tech, John=Sales, Martin=HR, Vaibhav=Tech}
size of employeeDeptmap: 4
Martin’s department: HR
Robin’s department: null
employeeDeptmap has John as key
employeeDeptmap has Sales as value
{}

使用 HashMap 编写声明式代码

Java 8的 Map接口引入了新方法,例如帮助您使用lambda 表达式compute(), computeIfPresent() and computeIfAbsent()编写代码。

计算()

假设您有一个团队的 HashMap 而没有。的目标如下。

HashMap<String,Integer> teamGoalMap=new HashMap<>();
teamGoalMap.put("team1",1);
teamGoalMap.put("team2",1);

现在您要添加 1 个目标,team1并且通常按如下方式进行。

teamGoalMap.put("team1",teamGoalMap.get("team1")+1);

相反,您可以使用以下计算轻松完成此操作。

teamGoalMap.compute("team1",(team,goal) ->goal+1);

因此,每当您想基于键值对应用映射时,都应该使用计算。

计算IfPresent()

如果指定的键存在且值不为空,则 computeIfPresent 重新计算值。 您之前可能编写过如下代码:

if(teamGoalMap.containsKey("team1"))
{
   teamGoalMap.put("team1",teamGoalMap.get("team1")+1);
}

你可以用computeIfPresent如下方式重写它

teamGoalMap.computeIfPresent("team1",(team,goal) ->goal+1);

如果函数返回 null,则键将从 HashMap 中删除。

计算如果没有()

如果指定的键不存在且函数不返回 null,则 computeIfAbsent 重新计算值。 您之前可能编写过如下代码:

if(!teamGoalMap.containsKey("team3"))
{
   teamGoalMap.put("team3",0);
}

你可以用computeIfAbsent如下方式重写它

teamGoalMap.computeIfAbsent("team3",value -> 0);

如果 key 已经存在于 map 中,那么什么都不会改变。

让我们看另一个以声明式样式重写 HashMap 代码的示例。

您可能已经以一种简单的方式编写了程序,如下所示。

package org.arpit.java2blog.HashMap;
import java.util.HashMap;
public class FrequencyOfEachWord {
   public static void main(String[] args) {
      String str = "thisisjavablog";

      HashMap<Character,Integer> hMap = new HashMap<>();
      for(int i= 0 ; i< str.length() ; i++) {
          Character c=str.charAt(i);
         if(hMap.containsKey(c)) {
            int count = hMap.get(c);
            hMap.put(c,count+1);
         } else {
            hMap.put(c,1);
         }
      }
      System.out.println(hMap);
   }
}

输出:

{a=2, b=1, s=2, t=1, v=1, g=1, h=1, i=2, j=1, l=1, o=1}

上面的程序使用简单的逻辑来计算字符串中每个字符的频率。

  1. 创建一个包含字符到计数映射的 HashMap。
  2. 逐个字符迭代字符串
  3. 如果地图中不存在字符,则计数应为 1
  4. 如果字符已经存在于地图中,则将其计数增加 1

computeIfPresent让我们使用andcomputeIfAbesent方法重写这个逻辑。

package org.arpit.java2blog.HashMap;
import java.util.HashMap;
public class FrequencyOfEachWord {
   public static void main(String[] args) {
      String str = "thisisjavablog";

      HashMap<Character,Integer> hMap = new HashMap<>();
      for(int i= 0 ; i< str.length() ; i++) {
          Character c=str.charAt(i);
        hMap.computeIfPresent(c, (character,count)-> count+1);
         hMap.computeIfAbsent(c, (character)-> 1);
      }
      System.out.println(hMap);
   }
}

输出:

{a=2, b=1, s=2, t=1, v=1, g=1, h=1, i=2, j=1, l=1, o=1}

如您所见,在computeIfPresentcomputeIfAbesent方法的情况下,逻辑看起来非常可读。

从HashMap中获取entrySet()、keySet()和values()

入口集()

entrySet()`: 由于 HashMap 以 的形式存储键值对`Entry`,我们可以通过调用来检索 entrySet()`map.entrySet()

键集()

keySet():提供一组键。

值()

values():提供值的集合。

这是相同的示例。

package org.arpit.java2blog;

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

public class HashMapEntrySetMain {

    public static void main(String[] args) {
        HashMap<Integer, String> studentIDNameMap = new HashMap<>();

        // Putting key-values pairs in HashMap
        studentIDNameMap.put(101,"Andy");
        studentIDNameMap.put(102, "Mary");
        studentIDNameMap.put(103, "Sam");
        studentIDNameMap.put(104,"Sandy");

        // get entrySet
        Set<Entry<Integer, String>> entrySet = studentIDNameMap.entrySet();
        System.out.println("EntrySet: "+entrySet);

        // get keySet
        Set<Integer> keySet = studentIDNameMap.keySet();
        System.out.println("keySet: "+keySet);

        // get values
        Collection<String> values = studentIDNameMap.values();
        System.out.println("values: "+values);
    }
}

输出:

EntrySet: [101=Andy, 102=Mary, 103=Sam, 104=Sandy] keySet: [101, 102, 103, 104] values: [Andy, Mary, Sam, Sandy]

遍历 HashMap

有很多方法可以遍历 HashMap

  1. 使用 HashMap 迭代keyset()
  2. keyset()使用foreach () 和lambda 表达式迭代 HashMap
  3. 使用foreach ( )和 lambda 表达式迭代 HashMap [java 8]
  4. 遍历 HashMap 的entrySet()使用iterator
  5. entrySet()使用 foreach() 和 lambda 表达式迭代 HashMap
  6. entrySet()使用 foreach 循环遍历HashMap
package org.arpit.java2blog.HashMap;

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

public class HashMapIterationMain {

    public static void main(String[] args) {

        HashMap<String, String> userCountryMap = new HashMap<>();

        // Putting key-values pairs in HashMap
        userCountryMap.put("Anchit","India");
        userCountryMap.put("Andy", "USA");
        userCountryMap.put("Roy", "Germary");
        userCountryMap.put("Mary","France");

        System.out.println("=========================================================");
        System.out.println("Iterating over HashMap with foreach and lambda:");
        userCountryMap.forEach((user,country) -> { 
            System.out.println(user+" --> "+country);
            } 
        );

        System.out.println("=========================================================");
        System.out.println("Iterating over HashMap using keyset() with foreach loop:");
        for(String user:userCountryMap.keySet())
        {
            System.out.println(user+" --> "+userCountryMap.get(user));
        }
        System.out.println("=========================================================");
        System.out.println("Iterating over HashMap's keyset() with foreach and lambda:");
        userCountryMap.keySet().forEach((user) -> { 
            System.out.println(user+" --> "+userCountryMap.get(user));
            } 
        );

        System.out.println("=========================================================");
        System.out.println("Iterating over HashMap's entrySet with iterator");
        Iterator<Entry<String, String>> iterator = userCountryMap.entrySet().iterator();
        while(iterator.hasNext())
        {
            Entry<String, String> next = iterator.next();
            System.out.println(next.getKey()+" --> "+next.getValue());
        }

        System.out.println("=========================================================");
        System.out.println("Iterating over HashMap's entrySet with foreach and lambda");
        userCountryMap.entrySet().forEach((entry) -> { 
            System.out.println(entry.getKey()+" --> "+entry.getValue());
            } 
        );

        System.out.println("=========================================================");
        System.out.println("Iterating over HashMap's entrySet with foreach loop");
        for(Map.Entry<String, String> entry:userCountryMap.entrySet())
        {
            System.out.println(entry.getKey()+" --> "+entry.getValue());
        }

    }
}

输出:

=========================================================
Iterating over HashMap with foreach and lambda:
Anchit –> India
Andy –> USA
Roy –> Germary
Mary –> France
=========================================================
Iterating over HashMap using keyset() with foreach loop:
Anchit –> India
Andy –> USA
Roy –> Germary
Mary –> France
=========================================================
Iterating over HashMap’s keyset() with foreach and lambda:
Anchit –> India
Andy –> USA
Roy –> Germary
Mary –> France
=========================================================
Iterating over HashMap’s entrySet with iterator
Anchit –> India
Andy –> USA
Roy –> Germary
Mary –> France
=========================================================
Iterating over HashMap’s entrySet with foreach and lambda
Anchit –> India
Andy –> USA
Roy –> Germary
Mary –> France
=========================================================
Iterating over HashMap’s entrySet with foreach loop
Anchit –> India
Andy –> USA
Roy –> Germary
Mary –> France

将自定义对象存储为 Key

您可以将自定义对象存储为 HashMap 中的 Key,但您应该实现hashcode 和 equals方法,否则它可能无法按预期工作。

创建一个名为Country.java

package org.arpit.java2blog;  
public class Country  {  

    String name;  
    long population;  

    public Country(String name, long population) {  
        super();  
        this.name = name;  
        this.population = population;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public long getPopulation() {  
        return population;  
    }  
    public void setPopulation(long population) {  
        this.population = population;  
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + (int) (population ^ (population >>> 32));
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Country other = (Country) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

   @Override
    public String toString() {

        return "Country: "+name+" | population:"+population;
    }
}

创建另一个类HashMapMain.java

package org.arpit.java2blog;

import java.util.HashMap;

public class HashMapMain {

    public static void main(String args[])
    {
        Country india=new Country("India",10000);
        Country japan=new Country("Japan",3000);
        Country france=new Country("France",5000);
        Country russia=new Country("Russia",4000);

        // HashMap with Country name as key and capital as value
        // HashMap stores elements in key value pairs
        HashMap<Country,String> countryCapitalMap=new HashMap<>();
        countryCapitalMap.put(india,"Delhi");
        countryCapitalMap.put(japan,"Tokyo");
        countryCapitalMap.put(france,"Paris");
        countryCapitalMap.put(russia,"Moscow");

        System.out.println("-----------------------------");
        // Iterating HashMap Using keySet() and for each loop
        System.out.println("Iterating HashMap Using keySet() and for each loop");
        for (Country countryKey:countryCapitalMap.keySet()) {
            System.out.println(countryKey +" and  Capital:"+countryCapitalMap.get(countryKey));

        }
        System.out.println("-----------------------------");
    }

}

当你运行上面的程序时,你会得到下面的输出

—————————–
Iterating HashMap Using keySet() and for each loop
Country: Japan | population:3000 and Capital:Tokyo
Country: India | population:10000 and Capital:Delhi
Country: Russia | population:4000 and Capital:Moscow
Country: France | population:5000 and Capital:Paris
—————————–

在java中对HashMap进行排序

按键

我们可以使用TreeMap对 HashMap 中的键进行排序。我们只需要将 HashMap 传递给 TreeMap 的构造函数。

按价值观

我们需要按照以下步骤按值对 HashMap 进行排序。

  1. entrySet()从 HashMap获取
  2. 将 entrySet 转换为List
  3. 在Comparator的帮助下对列表进行排序
  4. 遍历列表并将 Entry 对象放入LinkedHashMap

让我们写一个例子来按键和值对 HashMap 进行排序。我们将创建一个名为 Vehicle 的类,并将其用作 HashMap 中的 Key,而 value 将是 Vehicle 的所有者。

创建一个名为的类Vehicle.java

package org.arpit.java2blog;

public class Vehicle implements Comparable<Vehicle>{

    String name;
    long maxSpeed;

    public Vehicle(String name, long maxSpeed) {
        super();
        this.name = name;
        this.maxSpeed = maxSpeed;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public long getMaxSpeed() {
        return maxSpeed;
    }
    public void setMaxSpeed(long maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    @Override
    public String toString() {
        return "Vehicle name: "+name+"|Max speed: "+maxSpeed;
    }

    @Override
    public int compareTo(Vehicle v) {
        return this.getName().compareTo(v.getName());
    }
}

请注意,我们在这里实现了可比较的接口,它按名称比较了两辆汽车。这Comparable将用于在构造TreeMap时按 Keys 对其进行排序。 创建一个名为的类HashMapSortMain.java

package org.arpit.java2blog;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

public class HashMapSortMain {

    public static void main(String[] args) {

        Vehicle v1=new Vehicle("Car", 150);
        Vehicle v2=new Vehicle("Truck", 130);
        Vehicle v3=new Vehicle("Bike", 150);
        Vehicle v4=new Vehicle("Jeep", 180);

        // HashMap stores elements in key value pairs
        HashMap<Vehicle,String> vehicleOwnerMap=new HashMap<>();
        vehicleOwnerMap.put(v1,"John");
        vehicleOwnerMap.put(v2,"Chris");
        vehicleOwnerMap.put(v3,"Mary");
        vehicleOwnerMap.put(v4,"Harry");

        // Sort by keys 
        // As Vehicle class implements Comparable which defines sorting by vehicle name
        TreeMap<Vehicle,String> treeMap=new TreeMap<Vehicle,String>(vehicleOwnerMap);
        System.out.println("Sorted TreeMap by vehicle name: "+treeMap);

        // Sort by values
        Set<Entry<Vehicle, String>> entrySet = vehicleOwnerMap.entrySet();
        List<Entry<Vehicle, String>> vehicleEntryList=new ArrayList<>(entrySet);
        Collections.sort(vehicleEntryList,(e1,e2) -> 
                         e1.getValue().compareTo(e2.getValue()));

        LinkedHashMap<Vehicle, String> lmp=new LinkedHashMap<Vehicle, String>();
        vehicleEntryList.forEach((entry)-> {
            lmp.put(entry.getKey(), entry.getValue());
        });
        System.out.println("Sorted Map by owner name: "+lmp);
    }
}

输出:

Sorted TreeMap by vehicle name: {Vehicle name: Bike|Max speed: 150=Mary, Vehicle name: Car|Max speed: 150=John, Vehicle name: Jeep|Max speed: 180=Harry, Vehicle name: Truck|Max speed: 130=Chris}Sorted Map by owner name: {Vehicle name: Truck|Max speed: 130=Chris, Vehicle name: Jeep|Max speed: 180=Harry, Vehicle name: Car|Max speed: 150=John, Vehicle name: Bike|Max speed: 150=Mary}

HashMap 是线程安全的吗?

默认情况下 HashMap 不是线程安全的,在多线程环境中它会给出不确定的结果。 让我们借助一个示例来演示这一点:

package org.arpit.java2blog;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Counter {

    public static void main(String[] args) throws InterruptedException {

        Map<String, Integer> counterMap=new HashMap<>();

        counterMap.put("counter1",0);
        counterMap.put("counter2",100);

        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);

        Runnable counterTask = () ->
        {
            incrementTime(counterMap,"counter1");
            incrementTime(counterMap,"counter2");

        };

        for (int i = 1; i <= 100; i++) {
            newFixedThreadPool.submit(counterTask);
        }

        newFixedThreadPool.shutdown();
        newFixedThreadPool.awaitTermination(30, TimeUnit.SECONDS);

        System.out.println("Time for Counter1: "+counterMap.get("counter1"));
        System.out.println("Time for Counter2: "+counterMap.get("counter2"));
    }

    public static void incrementTime(Map<String,Integer> counterMap,String counter)
    {
        Integer count = counterMap.get(counter)
        count++;
        counterMap.put(counter,count);
    }
}

我在 map 中放置了两个条目,键分别为 counter1 和 counter2,值分别为时间 0 和 100。我们创建了一个任务,将两个计数器的时间都增加 1,我们使用ExecuterService提交 100 次。

让我们运行程序并检查输出:

Time for Counter1: 95
Time for Counter2: 195

但我们的预期输出应该是

Time for Counter1: 100
Time for Counter2: 200

因为我们已经提交了 100 次任务,并且在每次执行任务时,它都会调用 incrementTime ( ) ,并将时间加 1。 让我们再次运行程序。

Time for Counter1: 98
Time for Counter2: 197

它与上次执行不同,这是由于 HashMap 中的线程安全问题。

我们可以通过两种方式解决这个线程安全问题:

  1. Collections.synchronizedMap
  2. Collections.synchronizedMap()

Collections.synchronizedMap

我们可以使用Collections.synchronizedMap()使HashMap线程的所有操作安全,并使 incrementTime ( ) 方法同步来解决上述问题。 incrementTime ( ) 也应该同步,否则会有原子性问题。

package org.arpit.java2blog.HashMap;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Counter {

    public static void main(String[] args) throws InterruptedException {

        Map<String, Integer> counterMap=Collections.synchronizedMap(new HashMap<>());

        counterMap.put("counter1",0);
        counterMap.put("counter2",100);

        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);

        Runnable counterTask = () ->
        {
            incrementTime(counterMap,"counter1");
            incrementTime(counterMap,"counter2");

        };

        for (int i = 1; i <= 100; i++) {
            newFixedThreadPool.submit(counterTask);
        }

        newFixedThreadPool.shutdown();
        newFixedThreadPool.awaitTermination(30, TimeUnit.SECONDS);

        System.out.println("Time for Counter1: "+counterMap.get("counter1"));
        System.out.println("Time for Counter2: "+counterMap.get("counter2"));
    }

    public static synchronized void incrementTime(Map<String,Integer> counterMap,String counter)
    {
        Integer count = counterMap.get(counter);
        count++;
        counterMap.put(counter,count);
    }

}

输出:

Time for Counter1: 100
Time for Counter2: 200

如您所见,我们在使用Collections.synchronizedMap()incrementTime同步后得到了正确的输出。

Collections.synchronizedMap()

使用 Collections.synchronizedMap() 的缺点是它会锁定整个 hashmap 对象,这可能会导致性能问题,但ConcurrentHashMap只锁定映射的一部分并且在多线程环境中表现得很好。

Java 8 HashMap 更新

要了解这种变化,您需要了解 HashMap 内部的工作原理。Java 8在哈希冲突过多的情况下引入了良好的性能改进。

在 Java 7 之前,如果两个对象具有相同的 hashcode 并且不相等,那么两者将在单链表bucket的帮助下存储在同一位置。如果有太多的哈希冲突,那么性能可能会受到影响。 在最坏的情况下,如果所有键都具有相同的哈希码,则HashMap 中的操作可能需要O(n) 时间。get()``put() get()

Java 8 更新在 Java 8中,如果元素数量达到某个阈值 ,HashMap 会将链表更改为二叉树。在此更改的帮助下,HashMap 中的 get() 操作在最坏的情况下可能需要O(log(n)) 时间。

结论

您已经了解了 HashMap 的基础知识、如何创建 HashMap 并向其添加键值对、重要的 HashMap 方法、如何使用 HashMap 编写声明式代码、如何迭代 HashMap 和 HashMap 的线程安全问题以及如何同步一个哈希映射。

这就是java中的HashMap。


原文链接:https://codingdict.com/