Java HashMap Tutorial With Examples

Java HashMap is a hash table based implementation of Java’s Map interface. A Map, as you might know, is a collection of key-value pairs. It maps keys to values.

Java HashMap是基于哈希表的Java Map接口的实现。map是键值对的集合。它将映射到值。

Following are few key points to note about HashMaps in Java -

以下是有关Java中HashMap的一些要点

  • A HashMap cannot contain duplicate keys.

    HashMap不能包含重复的键

  • Java HashMap allows null values and the null key.

    Java Hash Map允许使用null值和null键

  • HashMap is an unordered collection. It does not guarantee any specific order of the elements.

    HashMap是一个无序集合。它不保证元素的任何特定顺序

  • Java HashMap is not thread-safe. You must explicitly synchronize concurrent modifications to the HashMap.

    Java HaspMap线程不是安全的。必须显示同步对HashMap的并发修改

Creating a HashMap and Adding key-value pairs to it

创建一个HashMap并向其添加键值对

The following example shows how to create a HashMap, and add new key-value pairs to it.

下面的示例演示如何创建HashMap以及如何向其添加新的键值对

package com.callicoder.hashmap;

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

public class CreateHashMapExample {

    public static void main(String[] args) {
        
        // Creating a HashMap
        Map<String, Integer> numberMapping = new HashMap<>();

        // Adding key-value pairs to a HashMap
        numberMapping.put("One", 1);
        numberMapping.put("Two", 2);
        numberMapping.put("Three", 3);

        // Add a new key-value pair only if the key does not exist in the HashMap, or is mapped to `null`
        // 仅当键在HashMap中不存在或映射为null时,才添加新的键值对
        numberMapping.putIfAbsent("Four", 4);

        System.out.println(numberMapping);
    }
}

Output

{One=1, Four=4, Two=2, Three=3}

Accessing keys and modifying their associated value in a HashMap

在HashMap中访问键并修改其关联的值

The example below shows:

  • How to check if a HashMap is empty | isEmpty()

    如何检查HashMap是否为空

  • How to find the size of a HashMap | size()

    如何得到HashMap的大小

  • How to check if a given key exists in a HashMap | containsKey()

    如何检查HashMap中是否存在给定的key

  • How to check if a given value exists in a HashMap | containsValue()

    如何检查HashMap中是否存在给定的值

  • How to get the value associated with a given key in the HashMap | get()

    如何获取与HashMap中给定键关联的值

  • How to modify the value associated with a given key in the HashMap | put()

    如何在HashMap中修改与给定键关联的值

package com.callicoder.hashmap;

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

public class AccessKeysFromHashMapExample {

    public static void main(String[] args) {

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

        // Check if a HashMap is empty
        System.out.println("is userCityMapping empty? : " + userCityMapping.isEmpty());

        userCityMapping.put("John", "New York");
        userCityMapping.put("Rajeev", "Bengaluru");
        userCityMapping.put("Steve", "London");

        System.out.println("userCityMapping HashMap : " + userCityMapping);

        // Find the size of a HashMap
        // 我们有3个用户的城市信息
        System.out.println("We have the city information of " + userCityMapping.size() + " users");

        String userName = "Steve";
        // Check if a key exists in the HashMap
        if(userCityMapping.containsKey(userName)) {
            // Get the value assigned to a given key in the HashMap
            // 获取分配给HashMap中给定键的值
            String city = userCityMapping.get(userName);
            System.out.println(userName + " lives in " + city);
        } else {
            System.out.println("City details not found for user " + userName);
        }

        // Check if a value exists in a HashMap
        if(userCityMapping.containsValue("New York")) {
            // userCityMapping中有一个住在纽约的用户
            System.out.println("There is a user in the userCityMapping who lives in New York");
        } else {
            System.out.println("There is no user in the userCityMapping who lives in New York");
        }

        // Modify the value assigned to an existing key
        userCityMapping.put(userName, "California");
        // Steve搬到新城市加州
        System.out.println(userName + " moved to a new city " + userCityMapping.get(userName) + ", New userCityMapping : " + userCityMapping);

        // The get() method returns `null` if the specified key was not found in the HashMap
        // 如果在HashMap中找不到指定的键,则get()方法返回`null`
       System.out.println("Lisa's city : " + userCityMapping.get("Lisa"));
    }
}

Output

is userCityMapping empty? : true
userCityMapping HashMap : {Steve=London, John=New York, Rajeev=Bengaluru}
We have the city information of 3 users
Steve lives in London
There is a user in the userCityMapping who lives in New York
Steve moved to a new city California, New userCityMapping : {Steve=California, John=New York, Rajeev=Bengaluru}
Lisa's city : null

Obtaining the entrySet, keySet, and values from a HashMap

从HashMap获取entrySet, keySet和values

The Map interface provides methods to retrieve the set of entries (key-value pairs), the set of keys, and the collection of values.

Map接口提供了检索条目集(键-值对),键集和值集合的方法

The following example shows how to retrieve them from a HashMap -

以下实例演示了如何从HashMap中检索它们

package com.callicoder.hashmap;

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

public class HashMapEntryKeySetValuesExample {

    public static void main(String[] args) {

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

        countryISOCodeMapping.put("India", "IN");
        countryISOCodeMapping.put("United States of America", "US");
        countryISOCodeMapping.put("Russia", "RU");
        countryISOCodeMapping.put("Japan", "JP");
        countryISOCodeMapping.put("China", "CN");

        // HashMap's entry set
        Set<Map.Entry<String, String>> countryISOCodeEntries = countryISOCodeMapping.entrySet();
        System.out.println("countryISOCode entries : " + countryISOCodeMapping);

        // HashMap's set
        Set<String> countries = countryISOCodeMapping.keySet();
        System.out.println("countries : " + countries);

        // HashMap's values
        Collection<String> isoCodes = countryISOCodeMapping.values();
        System.out.println("isoCodes : " + isoCodes);
    }
}

Output

countryISOCode entries : {United States of America=US, Japan=JP, China=CN, India=IN, Russia=RU}
countries : [United States of America, Japan, China, India, Russia]
isoCodes : [US, JP, CN, IN, RU]

Iterating over a HashMap

遍历HashMap

The following example shows different ways of iterating over a HashMap -

以下示例显示了对HashMap进行迭代的不同方法

  1. Iterating over a HashMap using Java 8 forEach and lambda expression.

    使用Java 8 forEach和lambda表达式遍历HashMap

  2. Iterating over the HashMap’s entrySet using iterator().

    使用iterator()遍历HashMap的entrySet

  3. Iterating over the HashMap’s entrySet using Java 8 forEach and lambda expression.

    使用Java 8 forEach和lambda表达式迭代HashMap的entrySet

  4. Iterating over the HashMap’s entrySet using simple for-each loop.

    使用简单的for-each循环迭代HashMap的entrySet

  5. Iterating over the HashMap’s keySet.

    遍历HashMap的keySet

package com.callicoder.hashmap;

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

public class IterateOverHashMap {

    public static void main(String[] args) {

        Map<String, Double> employeeSalary = new HashMap<>();
        employeeSalary.put("David", 76000.00);
        employeeSalary.put("John", 120000.00);
        employeeSalary.put("Mark", 95000.00);
        employeeSalary.put("Steven", 134000.00);

        // 使用Java 8 forEach和lambda遍历HashMap
        System.out.println("=== Iterating over a HashMap using Java 8 forEach and lambda ===");
        employeeSalary.forEach((employee, salary) ->{
            System.out.println(employee + " => " + salary);
        });

        // 使用iterator()遍历HashMap的entrySet
        System.out.println("\n=== Iterating over the HashMap's entrySet using iterator() ===");
        Set<Map.Entry<String, Double>> employeeeSalaryEntries = employeeSalary.entrySet();
        Iterator<Map.Entry<String, Double>> employeeSalaryIterator = employeeeSalaryEntries.iterator();
        while (employeeSalaryIterator.hasNext()) {
            Map.Entry<String, Double> entry = employeeSalaryIterator.next();
            System.out.println(entry.getKey() + " => " + entry.getValue());
        }

        // 使用Java 8 forEach和lambda迭代HashMap的entrySet
        System.out.println("\n=== Iterating over the HashMap's entrySet using Java 8 forEach and lambda ===");
        employeeSalary.entrySet().forEach(entry -> {
            System.out.println(entry.getKey() + " => " + entry.getValue());
        });

        // 使用简单的for-each循环迭代HashMap的entrySet
        System.out.println("\n=== Iterating over the HashMap's entrySet using simple for-each loop ===");
        for (Map.Entry<String, Double> entry : employeeSalary.entrySet()) {
            System.out.println(entry.getKey() + " => " + entry.getValue());
        }

        // 遍历HashMap的keySet
        System.out.println("\n=== Iterating over the HashMap's keySet ===");
        employeeSalary.keySet().forEach(employee -> {
            System.out.println(employee + " => " + employeeSalary.get(employee));
        });
    }
}

Output

=== Iterating over a HashMap using Java 8 forEach and lambda ===
David => 76000.0
John => 120000.0
Mark => 95000.0
Steven => 134000.0

=== Iterating over the HashMap's entrySet using iterator() ===
David => 76000.0
John => 120000.0
Mark => 95000.0
Steven => 134000.0

=== Iterating over the HashMap's entrySet using Java 8 forEach and lambda ===
David => 76000.0
John => 120000.0
Mark => 95000.0
Steven => 134000.0

=== Iterating over the HashMap's entrySet using simple for-each loop ===
David => 76000.0
John => 120000.0
Mark => 95000.0
Steven => 134000.0

=== Iterating over the HashMap's keySet ===
David => 76000.0
John => 120000.0
Mark => 95000.0
Steven => 134000.0

Java HashMap with User defined objects

Java HashMap与用户定义的对象

Check out the following example to learn how to create and work with a HashMap of user defined objects.

查看以下示例,以了解如何创建和使用用户定义对象的HashMap

package com.callicoder.hashmap;

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

class Employee {
    private Integer id;
    private String name;
    private String city;

    public Employee(Integer id, String name, String city) {
        this.id = id;
        this.name = name;
        this.city = city;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {

        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", city='" + city + '\'' +
                '}';
    }
}

public class HashMapUserDefinedObjectExample {

    public static void main(String[] args) {

        Map<Integer, Employee> employeesMap = new HashMap<>();

        employeesMap.put(1001, new Employee(1001, "Rajeev", "Bengaluru"));
        employeesMap.put(1002, new Employee(1002, "David", "New York"));
        employeesMap.put(1003, new Employee(1003, "Jack", "Paris"));

        System.out.println(employeesMap);
    }
}

Output

{1001=Employee{id=1001, name='Rajeev', city='Bengaluru'}, 1002=Employee{id=1002, name='David', city='New York'}, 1003=Employee{id=1003, name='Jack', city='Paris'}}

Synchronizing Access to Java HashMap

同步访问Java HashMap

Java HashMap is not thread-safe. It may become non-deterministic in multi-threaded environments where multiple threads try to modify the HashMap concurrently.

Java HashMap线程不是安全的。在多个线程尝试同时修改HashMap的多线程环境中,它可能变得不确定

Example demonstrating HashMap’s unpredictable behavior in multi-threaded environments

演示HashMap在多线程环境中的不可预测行为的示例

The following example demonstrates how HashMap becomes non-deterministic when multiple threads try to modify it at the same time -

以下示例演示了当多个线程尝试同时修改HashMap时,HashMap如何变得不确定的-

package com.callicoder.hashmap;

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 UnsafeHashMapExample {
    public static void main(String[] args) throws InterruptedException {
        Map<String, Integer> cricketTeamScore = new HashMap<>();
        cricketTeamScore.put("Australia", 349);
        cricketTeamScore.put("India", 250);

        // Create an ExecutorService with a Thread Pool of size 10
        // 创建一个大小为10的线程池的ExcecutorService
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        // Create a Runnable object that increments the value associated with a given key in the HashMap by one.
        // 创建一个Runnable对象,该对象将与HashMap中给定键关联的值加1
        Runnable task = () -> {
            incrementTeamScore(cricketTeamScore, "India");
        };

        // Submit the Runnable object to the executorService 100 times to test concurrent modifications
        // 将Runnable对象提交到executorService 100次以测试并发修改
        for(int i = 0; i < 100; i++) {
            executorService.submit(task);
        }

        executorService.shutdown();
        executorService.awaitTermination(60, TimeUnit.SECONDS);

        System.out.println("Final Score of Team India : " + cricketTeamScore.get("India"));
    }

    // Increment the score of a team by one
    private static void incrementTeamScore(Map<String, Integer> cricketTeamScore, String team) {
        Integer score = cricketTeamScore.get(team);
        cricketTeamScore.put(team, score + 1);
    }
}

The final output of the above program should be 350 because the initial value was 250, and we’re incrementing it 100 times.

上述程序的最终输出应为350,因为初始值为250,我们将其递增100

But since multiple threads try to modify the HashMap concurrently, the change done by one thread gets overridden by some other thread, and the output becomes non-deterministic.

但是由于多个线程尝试同时修改HashMap,因此一个线程所做的更改将被其它线程覆盖,并且输出将变得不确定

If you run the above program multiple times, you’ll find that it produces different output each time it is run.

如果您多次运行上述程序,则会发现它每次运行都会产生不同的输出。

Output

Final Score of Team India : 349

You can learn more about concurrency issues like this from my Java Concurrency Issues and Thread Synchronization tutorial.

Example demonstrating how to synchronize concurrent modifications to a HashMap

演示如何将并发修改同步到HashMap的示例

Let’s write the thread-safe version of the previous program. We can make the following two changes to the program to make it thread-safe -

编写先前程序的线程安全版本。可以对程序进行以下两项更改以使其具有线程安全性-

  • Use the Collections.synchronizedMap() method to obtain a synchronized view of the HashMap.
  • 使用Collections.synchronizedMap()方法获取HashMap的同步视图
  • Write the increment logic inside a synchronized block.
  • 将增量逻辑写入同步块中
package com.callicoder.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 SynchronizedHashMapExample {

    public static void main(String[] args) throws InterruptedException {
        Map<String, Integer> cricketTeamScore = Collections.synchronizedMap(new HashMap<>());
        cricketTeamScore.put("Australia", 349);
        cricketTeamScore.put("India", 250);

        // Create an ExecutorService with a Thread Pool of size 10
        // 创建一个大小为10的线程池的ExcecutorService
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        // Create a Runnable object that increments the value associated with a given key in the HashMap by one.
        // 创建一个Runnable对象,该对象将与HashMap中给定键关联的值加1
        Runnable task = () -> {
            incrementTeamScore(cricketTeamScore, "India");
        };

        // Submit the Runnable object to the executorService 100 times to test concurrent modifications
        for (int i = 0; i < 100; i++) {
            executorService.submit(task);
        }

        executorService.shutdown();
        executorService.awaitTermination(60, TimeUnit.SECONDS);

        System.out.println("Final Score of Team India : " + cricketTeamScore.get("India"));
    }

    // Increment the score of a team by one
    private static void incrementTeamScore(Map<String, Integer> cricketTeamScore, String team) {
        synchronized (cricketTeamScore) {
            Integer score = cricketTeamScore.get(team);
            cricketTeamScore.put(team, score + 1);
        }
    }
}

This program produces the correct output -

Final Score of Team India : 350

You can also use a ConcurrentHashMap for thread safety instead of the HashMap obtained via Collections.synchronizedMap() method. The ConcurrentHashMap provides thread-safe operations on the Map.

您也可以将ConcurrentHashMap用于线程安全,而不是通过Collections.synchronizedMap()方法获取的HashMap。ConcurrentHashMap在Map上提供线程安全操作。

猜你喜欢

转载自www.cnblogs.com/PrimerPlus/p/13202665.html
今日推荐