第四章 Java中的 LinkedHashMap


LinkedHashMap 是 Map 接口的基于 Hashtable 和链表的实现,具有可预测的插入顺序。它维护所有条目的双链表,这就是它与HashMap的不同之处。

Java LinkedHashMap

关于 LinkedHashMap 的几点

  1. LinkedHashMap 实现了 Map 接口并扩展了 HashMap类。
  2. LinkedHashMap 维护插入顺序,因此当您能够按插入顺序访问元素时,就像ArrayList一样。
  3. LinkedHashMap 维护双向链表以维护插入顺序。
  4. 它不是同步的,也不是线程安全的。
  5. 不允许重复键
  6. 允许一null键多值null

LinkedHashMap

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

LinkedHashMap 构造函数

Java LinkedHashMap 类有五个构造函数 public LinkedHashMap():这是默认构造函数,主要使用。它创建一个空的 LinkedHashMap,默认初始容量为 16,加载因子为 0.75。 public LinkedHashMap(int initialCapacity):该构造函数用于指定LinkedHashMap的初始容量和默认加载因子0.75。 public LinkedHashMap(int initialCapacity,float loadFactor):该构造函数用于指定 LinkedHashMap 的初始容量和加载因子。在大多数情况下,您应该避免使用此构造函数,除非您确定这一点,因为负载因子 0.75 提供了时间和空间之间的良好折衷。 public LinkedHashMap(Map<? extends K,? extends V> m):当您想从其他 Map(例如TreeMap或HashMap )创建 LinkedHashMap 时,使用此构造函数。 public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder):该构造函数用于指定HashMap的初始容量、加载因子和访问顺序。如果我们将访问顺序作为 true 传递,那么它将根据访问顺序列出条目。

将键值对添加到 LinkedHashMap

我们可以使用类似于HashMapput()的方法添加条目。例子:LinkedHashMap

package org.arpit.java2blog;
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapEntriesMain {

    public static void main(String[] args) {
        Map<Integer, String> studentMap = new LinkedHashMap<Integer, String>();
        // Putting key-values pairs in LinkedHashMap
        studentMap.put(1, "Arvind");
        studentMap.put(2, "Andy");
        studentMap.put(3, "Mohan");
        studentMap.put(4, "Virat");

        System.out.println(studentMap);
    }
}

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

{1=Arvind, 2=Andy, 3=Mohan, 4=Virat}

如您所见,所有条目都按预期按插入顺序打印。 如果您只想在 LinkedHashMap 中不存在条目时才添加条目怎么办? 您可以putIfAbsent()在这种情况下使用该方法。

💡你知道吗?

在 Java 7 之后,您可以使用菱形运算符(<>)来初始化 Map。 您可以更改 Map<Integer, String> studentMap = new LinkedHashMap<Integer, String>();Map<Integer, String> studentMap = new LinkedHashMap<>();

从 LinkedHashMap 中删除条目

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

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

package org.arpit.java2blog;
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapRemoveMain {

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

        travelFareMap.put("Bus", 120);
        travelFareMap.put("Car", 2200);
        travelFareMap.put("Rail", 680);
        travelFareMap.put("Flight", 4000);
        System.out.println(travelFareMap);

        // Remove car key
        Integer fareCar = travelFareMap.remove("Car");
        System.out.println("===============================");
        System.out.println("Vehicle Car with fare "+fareCar+" removed from HashMap");
        System.out.println(travelFareMap);
        System.out.println("================================");

        // Remove Rail if fate is 800
        boolean isCarRemoved = travelFareMap.remove("Rail",800);
        // Rail key won't be removed as associated value is 680
        System.out.println("Did car removed from LinkedHashMap: "+isCarRemoved);
        System.out.println(travelFareMap);
        System.out.println("===============================");

        // Remove Flight if fare is 4000
        boolean isFlightRemoved = travelFareMap.remove("Flight",4000);
        // flight key will be removed as associated value is 4000
        System.out.println("Did Flight removed from LinkedHashMap: "+isFlightRemoved);
        System.out.println(travelFareMap);
        System.out.println("===============================");

    }
}

输出:

{Bus=120, Car=2200, Rail=680, Flight=4000}
===============================
Vehicle Car with fare 2200 removed from HashMap
{Bus=120, Rail=680, Flight=4000}
================================
Did car removed from LinkedHashMap: false
{Bus=120, Rail=680, Flight=4000}
===============================
Did Flight removed from LinkedHashMap: true
{Bus=120, Rail=680}
===============================

重要的 LinkedHashMap 方法

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

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

package org.arpit.java2blog;

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapMethodsMain {

    public static void main(String[] args) {
        Map<String, String> profDeptmap = new LinkedHashMap<>();

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

        // Putting key-values pairs in HashMap
        profDeptmap.put("Arvind","Chemistry");
        profDeptmap.put("Venkat", "Physics");
        profDeptmap.put("Mary", "History");
        profDeptmap.put("David","Maths");

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

        // get value from LinkedHashMap
        System.out.println("Venkat's department: "+profDeptmap.get("Venkat"));
        // Hamlet department will be null as we don't have key as "Hamlet"
        System.out.println("Hamlet's department: "+profDeptmap.get("Hamlet"));

        if(profDeptmap.containsKey("David"))
        {
            System.out.println("profDeptmap has David as key");
        }

        if(profDeptmap.containsValue("History"))
        {
            System.out.println("profDeptmap has History as value");
        }

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

输出:

is profDeptmap empty: true
{Arvind=Chemistry, Venkat=Physics, Mary=History, David=Maths}
size of profDeptmap: 4
Venkat’s department: Physics
Hamlet’s department: null
profDeptmap has David as key
profDeptmap has History as value
{}

从 LinkedHashMap 中获取 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.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class LinkedHashMapMain {

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

        // Putting key-values pairs in LinkedHashMap
        studentIDNameMap.put(1001,"Andrew");
        studentIDNameMap.put(1002, "Martin");
        studentIDNameMap.put(1003, "Sameer");
        studentIDNameMap.put(1004,"Venkat");

        // 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: [1001=Andrew, 1002=Martin, 1003=Sameer, 1004=Venkat] keySet: [1001, 1002, 1003, 1004] 值: [Andrew, Martin, Sameer, Venkat]

如您所见,所有对或值都按插入顺序排列。

迭代 LinkedHashMap

有很多方法可以[迭代 LinkedHashMap

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

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

public class LinkedHashMapIterationMain {

    public static void main(String[] args) {

        Map<String, Long> countryPopulationMap = new LinkedHashMap<>();

        // Putting key-values pairs in LinkedHashMap
        countryPopulationMap.put("India",13000L);
        countryPopulationMap.put("China", 15000L);
        countryPopulationMap.put("Germany", 9000L);
        countryPopulationMap.put("France",7000L);

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

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

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

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

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

    }
}

输出:

=========================================================
Iterating over LinkedHashMap with foreach and lambda:
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
=========================================================
Iterating over LinkedHashMap using keyset() with foreach loop:
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
=========================================================
Iterating over LinkedHashMap keyset() with foreach and lambda:
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
=========================================================
Iterating over LinkedHashMap entrySet with iterator
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
=========================================================
Iterating over LinkedHashMap’s entrySet with foreach and lambda
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
=========================================================
Iterating over LinkedHashMap’s entrySet with foreach loop
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000

访问顺序 LinkedHashMap

如果要按访问顺序从 LinkedHashMap 检索条目,可以使用LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) 构造函数。 让我为您提供带有访问顺序的 LinkedHashMap 的实时用例。

您可以使用带有访问顺序的 LinkedHashMap 来实现LRU 缓存。 创建一个名为的类LRULHCache

package org.arpit.java2blog;
import java.util.LinkedHashMap; 
import java.util.Map; 

class LRULHCache<K,V> { 
    private LinkedHashMap<K, V> map; 
    public LRULHCache(int capacity) 
    { 
        map = new LinkedHashMap<K, V>(capacity, 0.75f, true) { 
            protected boolean removeEldestEntry(Map.Entry eldest) 
            { 
                return size() > capacity; 
            } 
        }; 
    } 

    // This method works in O(1) 
    public V get(K key) 
    { 
        return map.get(key); 
    } 

    // This method works in O(1) 
    public void set(K key, V value) 
    { 
        map.put(key, value); 
    } 

    @Override
    public String toString() {
        return "LinkedHashMap: "+map.toString();
    }
} 

public class LinkedHashMapAccessOrderMain { 

    public static void main(String[] args) 
    { 
        LRULHCache<Integer,Integer> lruLHCache = new LRULHCache<>(2);
        lruLHCache.set(2, 12000);
        lruLHCache.set(40, 70000);

        System.out.println(lruLHCache);

        // renews the entry
        System.out.println(lruLHCache.get(2));

        System.out.println(lruLHCache);

        lruLHCache.set(20, 70000);

        System.out.println(lruLHCache);

        System.out.println(lruLHCache.get(2));

        System.out.println(lruLHCache);

        System.out.println(lruLHCache.get(40));

    } 
}

输出

LinkedHashMap: {2=12000, 40=70000}
12000
LinkedHashMap: {40=70000, 2=12000}
LinkedHashMap: {2=12000, 20=70000}
12000
LinkedHashMap: {20=70000, 2=12000}
null

如您所见,我们创建了容量为 2 的 LRULHCache,一旦我们调用get(),LinkedHashMap 就会使用该密钥更新。

LinkedHashMap 是线程安全的吗?

LinkedHashMap 默认不是线程安全的,在多线程环境下它会给出不确定的结果。

如果多个线程尝试访问 LinkedHashMap 并且其中一个进行了结构修改,那么它应该是外部同步的。

在 LinkedHashMap 创建时执行此操作的最佳方法。

Map m=Collections.synchronizedMap(new LinkedHashMap());

我已经提供了一个HashMap 线程安全的例子,因为同样的例子也适用于 LinkedHashMap,你可以通过这个。

结论

您已经了解了 LinkedHashMap 的基础知识、如何创建 LinkedHashMap 并向其中添加键值对、重要的 LinkedHashMap 方法、如何迭代 LinkedHashMap 和 LinkedHashMap 的线程安全问题以及如何同步 LinkedHashMap。

这就是java中的HashMap。


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