第四章 java中的HashMap


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

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

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

keySet()

keySet():提供一组键。

values()

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

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() 的缺点是它会锁定整个 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/