实现 Map 并保持插入顺序的 Java 类?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/683518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 17:52:40  来源:igfitidea点击:

Java Class that implements Map and keeps insertion order?

javadictionarykey-value

提问by Shane

I'm looking for a class in java that has key-value association, but without using hashes. Here is what I'm currently doing:

我正在寻找具有键值关联但不使用哈希的 Java 类。这是我目前正在做的事情:

  1. Add values to a Hashtable.
  2. Get an iterator for the Hashtable.entrySet().
  3. Iterate through all values and:
    1. Get a Map.Entryfor the iterator.
    2. Create an object of type Module(a custom class) based on the value.
    3. Add the class to a JPanel.
  4. Show the panel.
  1. 将值添加到Hashtable.
  2. 获取Hashtable.entrySet().
  3. 遍历所有值并:
    1. Map.Entry为迭代器获取 a 。
    2. Module根据值创建类型对象(自定义类)。
    3. 将该类添加到 JPanel。
  4. 显示面板。

The problem with this is that I do not have control over the order that I get the values back, so I cannot display the values in the a given order (without hard-coding the order).

这样做的问题是我无法控制取回值的顺序,因此我无法按给定顺序显示值(没有对顺序进行硬编码)。

I would use an ArrayListor Vectorfor this, but later in the code I need to grab the Moduleobject for a given Key, which I can't do with an ArrayListor Vector.

我会为此使用ArrayListor Vector,但稍后在代码中我需要Module为给定的 Key获取对象,而我无法使用ArrayListor Vector

Does anyone know of a free/open-source Java class that will do this, or a way to get values out of a Hashtablebased on when they were added?

有没有人知道一个免费/开源的Java类可以做到这一点,或者一种Hashtable根据添加时间从 a 中获取值的方法?

Thanks!

谢谢!

采纳答案by Michael Myers

I suggest a LinkedHashMapor a TreeMap. A LinkedHashMapkeeps the keys in the order they were inserted, while a TreeMapis kept sorted via a Comparatoror the natural Comparableordering of the elements.

我建议 aLinkedHashMap或 a TreeMap。ALinkedHashMap保持键的插入顺序,而 aTreeMap保持通过 aComparatorComparable元素的自然顺序排序。

Since it doesn't have to keep the elements sorted, LinkedHashMapshould be faster for most cases; TreeMaphas O(log n)performance for containsKey, get, put, and remove, according to the Javadocs, while LinkedHashMapis O(1)for each.

由于它不必保持元素排序,LinkedHashMap因此在大多数情况下应该更快;TreeMapO(log n)表现为containsKeygetput,和remove,根据的Javadoc,而LinkedHashMapO(1)对每个。

If your API that only expects a predictable sort order, as opposed to a specific sort order, consider using the interfaces these two classes implement, NavigableMapor SortedMap. This will allow you not to leak specific implementations into your API and switch to either of those specific classes or a completely different implementation at will afterwards.

如果您的 API 只需要可预测的排序顺序,而不是特定的排序顺序,请考虑使用这两个类实现的接口,NavigableMapSortedMap. 这将允许您不会将特定实现泄漏到您的 API 中,并在之后随意切换到这些特定类或完全不同的实现。

回答by jpalecek

I don't know if it is opensource, but after a little googling, I found this implementation of Map using ArrayList. It seems to be pre-1.5 Java, so you might want to genericize it, which should be easy. Note that this implementation has O(N) access, but this shouldn't be a problem if you don't add hundreds of widgets to your JPanel, which you shouldn't anyway.

我不知道它是否是开源的,但经过一些谷歌搜索后,我发现使用 ArrayList 实现了 Map。它似乎是 Java 1.5 之前的版本,因此您可能希望对其进行泛化,这应该很容易。请注意,此实现具有 O(N) 访问权限,但如果您不向 JPanel 添加数百个小部件,这应该不是问题,无论如何您都不应该这样做。

回答by Peter Lawrey

You can maintain a Map(for fast lookup) and List(for order) but a LinkedHashMapmay be the simplest. You can also try a SortedMape.g. TreeMap, which an have any order you specify.

您可以维护 a Map(用于快速查找)和List(用于订单),但 aLinkedHashMap可能是最简单的。您也可以尝试使用SortedMapeg TreeMap,它具有您指定的任何顺序。

回答by Lawrence Dol

You could try my Linked Tree Mapimplementation.

你可以试试我的Linked Tree Map实现。

回答by jvdneste

If an immutable map fits your needsthen there is a library by google called guava(see also guava questions)

如果不可变地图满足您的需求,那么谷歌有一个名为guava的库(另请参阅guava questions

Guavaprovides an ImmutableMapwith reliable user-specified iteration order. This ImmutableMaphas O(1) performance for containsKey, get. Obviously put and remove are not supported.

Guava提供了一个具有可靠的用户指定迭代顺序的ImmutableMap。这个ImmutableMap对于 containsKey、get 的性能为 O(1)。显然不支持 put 和 remove。

ImmutableMapobjects are constructed by using either the elegant static convenience methods of()and copyOf()or a Builderobject.

ImmutableMap对象是通过使用优雅的静态方法()copyOf()Builder对象构造的。

回答by Praveen Kishor

LinkedHashMap will return the elements in the order they were inserted into the map when you iterate over the keySet(), entrySet() or values() of the map.

当您遍历映射的 keySet()、entrySet() 或 values() 时,LinkedHashMap 将按照它们插入映射的顺序返回元素。

Map<String, String> map = new LinkedHashMap<String, String>();

map.put("id", "1");
map.put("name", "rohan");
map.put("age", "26");

for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + " = " + entry.getValue());
}

This will print the elements in the order they were put into the map:

这将按照元素放入地图的顺序打印元素:

id = 1
name = rohan 
age = 26 

回答by j2emanue

Whenever i need to maintain the natural order of things that are known ahead of time, i use a EnumMap

每当我需要维护提前知道的事物的自然顺序时,我都会使用EnumMap

the keys will be enums and you can insert in any order you want but when you iterate it will iterate in the enum order (the natural order).

键将是枚举,您可以按您想要的任何顺序插入,但是当您迭代时,它将以枚举顺序(自然顺序)进行迭代。

Also when using EnumMap there should be no collisions which can be more efficient.

此外,当使用 EnumMap 时,应该没有冲突,这可能会更有效。

I really find that using enumMap makes for clean readable code. Here is an example

我真的发现使用 enumMap 可以使代码清晰易读。这是一个例子

回答by Pankaj Goyal

You can use LinkedHashMapto main insertion order in Map

您可以使用LinkedHashMap作为 Map 中的主要插入顺序

The important points about Java LinkedHashMap class are:

Java LinkedHashMap 类的要点是:

  1. It contains onlyunique elements.
  2. A LinkedHashMap contains values based on the key 3.It may have one null key and multiple null values. 4.It is same as HashMap instead maintains insertion order

    public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> 
    
  1. 它只包含独特的元素。
  2. LinkedHashMap 包含基于键 3 的值。它可能有一个空键和多个空值。4.和HashMap一样,只是维护插入顺序

    public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> 
    

But if you want sort values in map using User-defined object or any primitive data type key then you should use TreeMapFor more information, refer this link

但是,如果您想使用用户定义的对象或任何原始数据类型键对地图中的值进行排序,那么您应该使用TreeMap有关更多信息,请参阅此链接

回答by Yash

Either You can use LinkedHashMap<K, V>or you can implement you own CustomMapwhich maintains insertion order.

您可以使用LinkedHashMap<K, V>或实现自己的CustomMap来维护插入顺序。

You can use the Following CustomHashMapwith the following features:

您可以使用CustomHashMap具有以下功能的以下内容:

  • Insertion order is maintained, by using LinkedHashMap internally.
  • Keys with nullor empty strings are not allowed.
  • Once key with value is created, we are not overriding its value.
  • 通过在内部使用 LinkedHashMap 来维护插入顺序。
  • null不允许使用带有或空字符串的键。
  • 一旦创建了带值的键,我们就不会覆盖它的值。

HashMapvs LinkedHashMapvs CustomHashMap

HashMap对比LinkedHashMap对比CustomHashMap

interface CustomMap<K, V> extends Map<K, V> {
    public boolean insertionRule(K key, V value);
}

@SuppressWarnings({ "rawtypes", "unchecked" })
public class CustomHashMap<K, V> implements CustomMap<K, V> {
    private Map<K, V> entryMap;
    // SET: Adds the specified element to this set if it is not already present.
    private Set<K> entrySet;

    public CustomHashMap() {
        super();
        entryMap = new LinkedHashMap<K, V>();
        entrySet = new HashSet();
    }

    @Override
    public boolean insertionRule(K key, V value) {
        // KEY as null and EMPTY String is not allowed.
        if (key == null || (key instanceof String && ((String) key).trim().equals("") ) ) {
            return false;
        }

        // If key already available then, we are not overriding its value.
        if (entrySet.contains(key)) { // Then override its value, but we are not allowing
            return false;
        } else { // Add the entry
            entrySet.add(key);
            entryMap.put(key, value);
            return true;
        }
    }
    public V put(K key, V value) {
        V oldValue = entryMap.get(key);
        insertionRule(key, value);
        return oldValue;
    }
    public void putAll(Map<? extends K, ? extends V> t) {
        for (Iterator i = t.keySet().iterator(); i.hasNext();) {
            K key = (K) i.next();
            insertionRule(key, t.get(key));
        }
    }

    public void clear() {
        entryMap.clear();
        entrySet.clear();
    }
    public boolean containsKey(Object key) {
        return entryMap.containsKey(key);
    }
    public boolean containsValue(Object value) {
        return entryMap.containsValue(value);
    }
    public Set entrySet() {
        return entryMap.entrySet();
    }
    public boolean equals(Object o) {
        return entryMap.equals(o);
    }
    public V get(Object key) {
        return entryMap.get(key);
    }
    public int hashCode() {
        return entryMap.hashCode();
    }
    public boolean isEmpty() {
        return entryMap.isEmpty();
    }
    public Set keySet() {
        return entrySet;
    }
    public V remove(Object key) {
        entrySet.remove(key);
        return entryMap.remove(key);
    }
    public int size() {
        return entryMap.size();
    }
    public Collection values() {
        return entryMap.values();
    }
}

Usage of CustomHashMap:

用法CustomHashMap

public static void main(String[] args) {
    System.out.println("== LinkedHashMap ==");
    Map<Object, String> map2 = new LinkedHashMap<Object, String>();
    addData(map2);

    System.out.println("== CustomHashMap ==");
    Map<Object, String> map = new CustomHashMap<Object, String>();
    addData(map);
}
public static void addData(Map<Object, String> map) {
    map.put(null, "1");
    map.put("name", "Yash");
    map.put("1", "1 - Str");
    map.put("1", "2 - Str"); // Overriding value
    map.put("", "1"); // Empty String
    map.put(" ", "1"); // Empty String
    map.put(1, "Int");
    map.put(null, "2"); // Null

    for (Map.Entry<Object, String> entry : map.entrySet()) {
        System.out.println(entry.getKey() + " = " + entry.getValue());
    }
}

O/P:

开/关:

== LinkedHashMap == | == CustomHashMap ==
null = 2            | name = Yash
name = Yash         | 1 = 1 - Str
1 = 2 - Str         | 1 = Int
 = 1                |
  = 1               |
1 = Int             |


If you know the KEY's are fixed then you can use EnumMap. Get the values form Properties/XML files

如果您知道 KEY 是固定的,那么您可以使用 EnumMap。从属性/XML 文件中获取值

EX:

前任:

enum ORACLE {
    IP, URL, USER_NAME, PASSWORD, DB_Name;
}

EnumMap<ORACLE, String> props = new EnumMap<ORACLE, String>(ORACLE.class);
props.put(ORACLE.IP, "127.0.0.1");
props.put(ORACLE.URL, "...");
props.put(ORACLE.USER_NAME, "Scott");
props.put(ORACLE.PASSWORD, "Tiget");
props.put(ORACLE.DB_Name, "MyDB");