Map을 구현하고 삽입 순서를 유지하는 Java 클래스?


463

키 값 연결이 있지만 해시를 사용하지 않는 Java 클래스를 찾고 있습니다. 내가 현재하고있는 일은 다음과 같습니다.

  1. 에 값 추가 Hashtable .
  2. 에 대한 반복자를 가져옵니다 Hashtable.entrySet() .
  3. 모든 값을 반복하고 다음을 수행하십시오.
    1. 도착 Map.Entry이터레이터를 .
    2. 유형의 객체 생성 Module값을 기준으로 (사용자 정의 클래스)를 .
    3. 클래스를 JPanel에 추가하십시오.
  4. 패널을 표시하십시오.

이것의 문제는 값을 다시 얻는 순서를 제어 할 수 없으므로 주어진 순서로 값을 표시 할 수 없다는 것입니다 (주문 하드 코딩없이).

나는 사용하는 것 ArrayList또는 Vector이것에 대한,하지만 나중에 코드에서 나는 잡을 필요가 Module내가 함께 할 수없는 주어진 키에 대한 객체를 ArrayList하거나 Vector.

누구 든지이 작업을 수행 할 무료 / 오픈 소스 Java 클래스 또는 값을 얻는 방법을 알고 있습니까? Hashtable 추가 된 시점을 기준으로 있습니까?

감사!


1
entryset / map.entry를 사용할 필요가 없습니다. hashtable.keys를 열거 형으로 사용하거나 hashtable.keyset.iterator를 사용하여 키와 값을 반복 할 수 있습니다.
John Gardner

5
해시를 사용하지 않는 것이 실제로 문제가 아니라 삽입 순서를 유지하기 때문에 제목을 변경하는 자유를 얻었습니다.
Joachim Sauer 2016 년

비슷한 질문, Java Ordered Map
Basil Bourque

답변:


734

나는 LinkedHashMap또는을 제안한다 TreeMap. A LinkedHashMap는 삽입 된 순서대로 키를 유지하고 a TreeMap는 요소 Comparator의 자연 Comparable순서 또는 정렬을 통해 정렬됩니다 .

요소를 정렬 된 상태로 유지할 필요가 없으므로 LinkedHashMap대부분의 경우 더 빠릅니다. TreeMap보유 O(log n)성능 containsKey, get, put, 및 remove, JavaDoc을 따라,이 동안 LinkedHashMap이다O(1) 마다.

특정 정렬 순서와 반대로 만, 예측 가능한 정렬 순서를 예상하여 API는, 인터페이스를 사용하는 것을 고려하면이 두 클래스는 구현, NavigableMap또는 SortedMap. 이를 통해 특정 구현을 API로 유출하지 않고 해당 특정 클래스 중 하나 또는 나중에 완전히 다른 구현으로 전환 할 수 있습니다.


2
javadocs에 따르면 (값 () 호출을 통해) 정렬 된 값만 제공하기 때문에 나에게는 효과가 없습니다. 주문한 Map.Entry 인스턴스를 얻는 방법이 있습니까?
코리 켄달

1
@CoryKendall : TreeMap이 작동하지 않습니까? 값이 아닌 키를 기준으로 정렬됩니다.
Michael Myers

1
내 실수는 세트가 분류되지 않은 것으로 생각했습니다.
Cory Kendall

61
참고 : TreeMap의 정렬은 키의 자연 순서를 기반으로합니다. "키는 자연 키 순서에 따라 정렬됩니다". LinkedHashMap은 정렬 된 삽입 순서입니다. 큰 차이!
Jop van Raaij

3
@AlexR : LinkedHashMap이 해당 목적을 위해 제공되는 특수 생성자 를 사용하여 작성된 경우에만 해당됩니다 . 기본적으로 반복은 삽입 순서입니다.
Michael Myers

22

LinkedHashMap은지도의 keySet (), entrySet () 또는 values ​​()를 반복 할 때지도에 삽입 된 순서대로 요소를 반환합니다.

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 

16

불변의 맵이 귀하의 요구에 맞는 경우 구글에 의해 구아바 라는 도서관이 있습니다 ( 구아바 질문 참조 )

Guava 는 신뢰할 수있는 사용자 지정 반복 순서와 함께 ImmutableMap 을 제공합니다 . 이 ImmutableMap 은 containsKey에 대해 O (1) 성능을 갖습니다. 분명히 넣고 제거는 지원되지 않습니다.

ImmutableMap 객체는 우아한 정적 편의 메서드 of ()copyOf () 또는 Builder 객체 를 사용하여 구성됩니다 .


6

Map(빠른 조회 List를 위해) 및 (순서를 위해) 유지할 수 있지만 a LinkedHashMap가 가장 간단 할 수 있습니다. 또한 시도 할 수 있습니다 SortedMap예를 들어 TreeMap사용자가 지정한 임의의 순서를 가지고있는.


1

오픈 소스인지는 모르겠지만 약간의 인터넷 검색 결과 ArrayList 사용 하여이 Map 구현을 발견 했습니다 . 1.5 이전의 Java 인 것 같으므로 일반화 할 수 있습니다. 이 구현에는 O (N) 액세스 권한이 있지만 JPanel에 수백 개의 위젯을 추가하지 않아도 문제가되지 않습니다.



1

미리 알려진 것의 자연스러운 순서를 유지해야 할 때마다 EnumMap을 사용합니다.

키는 열거 형이며 원하는 순서로 삽입 할 수 있지만 반복 할 때 열거 형 순서 (자연 순서)로 반복됩니다.

또한 EnumMap을 사용할 때 더 효율적인 충돌이 없어야합니다.

enumMap을 사용하면 코드를 깨끗하게 읽을 수 있습니다. 여기에 예가 있습니다


1

LinkedHashMap 을 사용하여 Map의 기본 게재 신청서에

Java LinkedHashMap 클래스의 중요한 점은 다음과 같습니다.

  1. 고유 한 요소 만 포함합니다.
  2. LinkedHashMap에는 키 3을 기반으로하는 값이 포함됩니다. 하나의 널 키와 여러 개의 널 값이있을 수 있습니다. 4. HashMap과 동일하지만 삽입 순서를 유지합니다.

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

그러나 사용자 정의 객체 또는 기본 데이터 유형 키를 사용하여 맵에서 정렬 값을 원하면 TreeMap 을 사용해야합니다. 자세한 정보는 이 링크를 참조하십시오.


0

CustomMap을 사용 LinkedHashMap<K, V>하거나 직접 구현할 수 있습니다. 신청서를 유지 관리하는 을 .

CustomHashMap다음 기능으로 다음 을 사용할 수 있습니다 .

  • 내부적으로 LinkedHashMap을 사용하여 삽입 순서가 유지됩니다.
  • null문자열이 있거나 비어있는 는 허용되지 않습니다.
  • 값이있는 키가 생성되면 해당 값을 재정의하지 않습니다.

HashMapvs LinkedHashMapvsCustomHashMap

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 파일 형식의 값 가져 오기

전의:

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");
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.