[java] HashMap 키와 같이 대소 문자를 구분하지 않는 문자열

다음과 같은 이유로 대소 문자를 구분하지 않는 문자열을 HashMap 키로 사용하고 싶습니다.

  • 초기화하는 동안 내 프로그램은 사용자 정의 문자열로 HashMap을 만듭니다.
  • 이벤트 (내 경우에는 네트워크 트래픽)를 처리하는 동안 다른 경우에는 String을 받았을 수도 있지만 <key, value>트래픽에서받은 사례를 무시하고 HashMap에서 from 을 찾을 수 있어야 합니다.

나는이 접근법을 따랐다.

CaseInsensitiveString.java

    public final class CaseInsensitiveString {
            private String s;

            public CaseInsensitiveString(String s) {
                            if (s == null)
                            throw new NullPointerException();
                            this.s = s;
            }

            public boolean equals(Object o) {
                            return o instanceof CaseInsensitiveString &&
                            ((CaseInsensitiveString)o).s.equalsIgnoreCase(s);
            }

            private volatile int hashCode = 0;

            public int hashCode() {
                            if (hashCode == 0)
                            hashCode = s.toUpperCase().hashCode();

                            return hashCode;
            }

            public String toString() {
                            return s;
            }
    }

LookupCode.java

    node = nodeMap.get(new CaseInsensitiveString(stringFromEvent.toString()));

이 때문에 모든 이벤트에 대해 CaseInsensitiveString의 새 객체를 만들고 있습니다. 따라서 성능이 저하 될 수 있습니다.

이 문제를 해결하는 다른 방법이 있습니까?



답변

Map<String, String> nodeMap = 
    new TreeMap<>(String.CASE_INSENSITIVE_ORDER);

그게 당신이 필요한 전부입니다.


답변

Guido García가 제안한대로 여기대한 답변 :

import java.util.HashMap;

public class CaseInsensitiveMap extends HashMap<String, String> {

    @Override
    public String put(String key, String value) {
       return super.put(key.toLowerCase(), value);
    }

    // not @Override because that would require the key parameter to be of type Object
    public String get(String key) {
       return super.get(key.toLowerCase());
    }
}

또는

https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/map/CaseInsensitiveMap.html


답변

한 가지 방법은 Apache Commons AbstractHashedMap클래스 의 사용자 정의 서브 클래스를 작성하여 대소 문자를 구분하지 않는 해시 및 키 비교를 수행하기 위해 hashisEqualKeys메소드를 대체하는 것입니다. (참고-나는 이것을 직접 시도한 적이 없다 …)

이를 통해 맵 조회 또는 업데이트를 수행 할 때마다 새 객체를 생성하는 오버 헤드를 피할 수 있습니다. 그리고 일반적인 Map작업은 일반처럼 O (1) …이어야합니다 HashMap.

그리고 그들이 선택한 구현 선택을 받아 들일 준비가 되었다면 Apache Commons CaseInsensitiveMap는 사용자 정의 / 전문화 작업 AbstractHashedMap을 수행합니다.


그러나 O (logN) getput연산이 허용되는 TreeMap경우 대소 문자를 구분하지 않는 문자열 비교기가 옵션입니다. 예를 들어 String.CASE_INSENSITIVE_ORDER.

새 임시 String 객체에게 당신이 할 때마다 생성 괜찮다면 그리고 putget, 다음 이씨의 대답은 잘합니다. (하지만, 그렇게 한 경우 원래 키 케이스를 유지하지 않을 것입니다 …)


답변

서브 클래스는 HashMap그 낮은 경우상의 키 버전을 생성 put하고 get(그리고 아마도 다른 키 지향 방법).

또는 a HashMap를 새 클래스에 합성하고 모든 것을지도에 위임하지만 키를 번역하십시오.

원래 키를 유지해야하는 경우 이중 맵을 유지하거나 원래 키를 값과 함께 저장할 수 있습니다.


답변

두 가지 선택이 떠 오릅니다.

  1. s.toUpperCase().hashCode();의 키로 직접을 사용할 수 있습니다 Map.
  2. 대소 문자를 무시 TreeMap<String>하는 사용자 정의와 함께를 사용할 수 있습니다 Comparator.

그렇지 않으면 새로운 종류의 문자열을 정의하는 대신 솔루션을 선호하는 경우 필요한 대소 문자를 구분하지 않는 기능으로 새 맵을 구현합니다.


답변

해시 코드를 기억하기 위해 문자열을 “랩핑”하는 것이 좋지 않을 것입니다. 일반적인 String 클래스에서 hashCode ()는 처음으로 O (N)이고 나중에 사용하기 위해 유지되므로 O (1)입니다.

public class HashWrap {
    private final String value;
    private final int hash;

    public String get() {
        return value;
    }

    public HashWrap(String value) {
        this.value = value;
        String lc = value.toLowerCase();
        this.hash = lc.hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof HashWrap) {
            HashWrap that = (HashWrap) o;
            return value.equalsIgnoreCase(that.value);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return this.hash;
    }

    //might want to implement compare too if you want to use with SortedMaps/Sets.
}

이를 통해 Java에서 Hashtable의 모든 구현을 사용하고 O (1) hasCode ()를 가질 수 있습니다.


답변

Eclipse Collections 에서 HashingStrategy 를 사용할 수 있습니다Map

HashingStrategy<String> hashingStrategy =
    HashingStrategies.fromFunction(String::toUpperCase);
MutableMap<String, String> node = HashingStrategyMaps.mutable.of(hashingStrategy);

참고 : 저는 Eclipse Collections에 기고자입니다.