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

时间:2009-03-25 21:22:04

标签: java dictionary key-value

我正在寻找一个具有键值关联的java类,但不使用哈希。以下是我目前正在做的事情:

  1. 将值添加到Hashtable
  2. 获取Hashtable.entrySet()
  3. 的迭代器
  4. 遍历所有值并:
    1. 为迭代器获取Map.Entry
    2. 根据值创建类型为Module(自定义类)的对象。
    3. 将课程添加到JPanel。
  5. 显示面板。
  6. 这个问题是我无法控制返回值的顺序,因此我无法按给定的顺序显示值(不对代码进行硬编码)。

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

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

    谢谢!

9 个答案:

答案 0 :(得分:654)

我建议使用LinkedHashMapTreeMapLinkedHashMap会按照插入顺序保留密钥,而TreeMap会按照Comparator或元素的自然Comparable顺序进行排序。

由于不必对元素进行排序,因此LinkedHashMap对于大多数情况应该更快;根据Javadocs,TreeMap O(log n)containsKeygetput的效果为removeLinkedHashMap为每个O(1)

如果您的API仅期望可预测的排序顺序(而不是特定的排序顺序),请考虑使用这两个类实现的接口NavigableMapSortedMap。这将允许您不要将特定实现泄漏到API中,然后切换到这些特定类中的任何一个,或者随后切换到完全不同的实现。

答案 1 :(得分:15)

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

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

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

答案 2 :(得分:15)

当您遍历地图的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 

答案 3 :(得分:6)

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

答案 4 :(得分:1)

我不知道它是否是开源,但经过一番谷歌搜索后,我发现this implementation of Map using ArrayList。它似乎是1.5之前的Java,所以你可能想要将它泛化,这应该很容易。请注意,此实现具有O(N)访问权限,但如果您不向JPanel添加数百个小部件,则这不应该是一个问题,您不应该这样做。

答案 5 :(得分:1)

您可以尝试我的Linked Tree Map实施。

答案 6 :(得分:1)

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

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

同样在使用EnumMap时,不应该有更高效的冲突。

我真的发现使用enumMap可以实现干净的可读代码。 这是example

答案 7 :(得分:1)

您可以使用 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());
    }
}

O / P:

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

如果您知道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");

答案 8 :(得分:0)

您可以将 LinkedHashMap 用于地图

中的主要广告订单

Java LinkedHashMap类的重点是:

  1. 它只包含唯一的元素。
  2. LinkedHashMap包含基于密钥的值 3.它可能有一个空键和多个空值。 4.它与HashMap相同,而是维护插入顺序

    public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> 
    
  3. 但是如果你想在地图中使用用户定义的对象或任何原始数据类型键来排序值,那么你应该使用 TreeMap 有关更多信息,请参考this link