出于以下原因,我想使用不区分大小写的字符串作为HashMap键。

在初始化过程中,我的程序用用户定义的字符串创建HashMap 在处理事件(在我的情况下是网络流量)时,我可能会在不同的情况下收到字符串,但我应该能够定位<键,值>从HashMap忽略我从流量收到的情况。

我采用了这种方法

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的新对象。因此,它可能会影响性能。

有没有其他办法解决这个问题?


当前回答

继承HashMap的子类,并创建一个在put和get(可能还有其他面向键的方法)时小写键的版本。

或者将HashMap合成到新类中,并将所有内容委托给映射,但要转换键。

如果需要保留原始键,可以维护双映射,或者将原始键与值一起存储。

其他回答

我想到了两个选择:

你可以直接使用s.toUpperCase().hashCode();作为地图的钥匙。 你可以使用TreeMap<String>和一个忽略大小写的自定义比较器。

否则,如果您更喜欢自己的解决方案,我宁愿不定义一种新的String,而是实现一个具有所需的大小写不敏感功能的新Map。

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

这就是你所需要的。

继承HashMap的子类,并创建一个在put和get(可能还有其他面向键的方法)时小写键的版本。

或者将HashMap合成到新类中,并将所有内容委托给映射,但要转换键。

如果需要保留原始键,可以维护双映射,或者将原始键与值一起存储。

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

Or

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

因此,我为每个事件创建了CaseInsensitiveString的新对象。因此,它可能会影响性能。

创建包装器或在查找前将键转换为小写都会创建新对象。编写自己的java.util.Map实现是避免这种情况的唯一方法。这并不难,而且在我看来是值得的。我发现下面的哈希函数工作得很好,最多几百个键。

static int ciHashCode(String string)
{
    // length and the low 5 bits of hashCode() are case insensitive
    return (string.hashCode() & 0x1f)*33 + string.length();
}