ChatGPT解决这个技术问题 Extra ChatGPT

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

我正在寻找一个具有键值关联但不使用散列的java类。这是我目前正在做的事情:

将值添加到哈希表。获取 Hashtable.entrySet() 的迭代器。遍历所有值并: 获取迭代器的 Map.Entry。根据该值创建一个 Module 类型的对象(自定义类)。将类添加到 JPanel。显示面板。

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

为此,我会使用 ArrayListVector,但稍后在代码中我需要为给定的 Key 获取 Module 对象,而 ArrayListVector 无法做到这一点。

有谁知道可以执行此操作的免费/开源 Java 类,或者根据添加时间从 Hashtable 中获取值的方法?

谢谢!

您不需要使用 entryset/map.entry。您可以使用 hashtable.keys 作为枚举或使用 hashtable.keyset.iterator 来迭代键和值。
我冒昧地更改了标题,因为不使用哈希实际上不是问题,而是保持插入顺序。
类似问题,Java Ordered Map

t
toniedzwiedz

我建议使用 LinkedHashMapTreeMapLinkedHashMap 保持键的插入顺序,而 TreeMap 通过 Comparator 或元素的自然 Comparable 顺序保持排序。

由于它不必保持元素排序,LinkedHashMap 在大多数情况下应该更快;根据 Javadocs,TreeMapcontainsKeygetputremove 具有 O(log n) 的性能,而 LinkedHashMap 的性能分别为 O(1)

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


这对我不起作用,因为根据 javadocs,这只会给出有序值(通过 values() 调用)。有没有办法获得有序的 Map.Entry 实例?
@CoryKendall:TreeMap 不起作用吗?它应该按键排序,而不是按值排序。
请注意:TreeMap 的排序是基于键的自然顺序:“地图是根据其键的自然顺序排序的”。 LinkedHashMap 是按插入顺序排序的。巨大差距!
我相信 LinkedHashMap 没有实现 NavigableMapSortedMap
@AlexR:仅当使用为此目的提供的 special constructor 创建 LinkedHashMap 时,这才是正确的。默认情况下,迭代是按插入顺序进行的。
P
Praveen Kishor

当您遍历地图的 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());
}

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

id = 1
name = rohan 
age = 26 

V
Vipul Asri

如果不可变地图适合您的需要,那么 Google 提供了一个名为 guava 的库(另请参阅 guava questions

Guava 提供具有可靠的用户指定迭代顺序的 ImmutableMap。对于 containsKey, get,此 ImmutableMap 的性能为 O(1)。显然不支持放置和删除。

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


D
Daniel De León

您可以将 LinkedHashMap 用于 Map 中的主要插入顺序

Java LinkedHashMap 类的要点是:

它只包含独特的元素。 LinkedHashMap 包含基于键的值。它可能有一个空键和多个空值。它与 HashMap 相同,而是维护插入顺序 public class LinkedHashMap extends HashMap implements Map

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


V
Vladimir Vagaytsev

您可以维护 Map(用于快速查找)和 List(用于排序),但 LinkedHashMap 可能是最简单的。您也可以尝试 SortedMap,例如 TreeMap,它具有您指定的任何顺序。


Y
Yash

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

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

通过在内部使用 LinkedHashMap 来维护插入顺序。

不允许使用具有 null 或空字符串的键。

一旦创建了带值的键,我们就不会覆盖它的值。

HashMap vs LinkedHashMap vs 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();
    }
}

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

输出/输出:

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

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

前任:

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");

j
jpalecek

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


j
j2emanue

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

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

此外,当使用 EnumMap 时,不应该有更有效的冲突。

我真的发现使用 enumMap 可以生成清晰可读的代码。这是一个example