出于以下原因,我想使用不区分大小写的字符串作为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的新对象。因此,它可能会影响性能。
有没有其他办法解决这个问题?
你可以使用CollationKey对象来代替字符串:
Locale locale = ...;
Collator collator = Collator.getInstance(locale);
collator.setStrength(Collator.SECONDARY); // Case-insensitive.
collator.setDecomposition(Collator.FULL_DECOMPOSITION);
CollationKey collationKey = collator.getCollationKey(stringKey);
hashMap.put(collationKey, value);
hashMap.get(collationKey);
使用排序器。忽略口音差异。
CollationKey API并不保证实现hashCode()和equals(),但实际上您将使用RuleBasedCollationKey,它实现了这些。如果你是偏执的,你可以使用TreeMap,它保证以O(log n)时间而不是O(1)的成本工作。
根据其他答案,基本上有两种方法:继承HashMap或包装String。第一个需要多做一些工作。事实上,如果您想正确地执行它,您必须重写几乎所有的方法(containsKey、entrySet、get、put、putAll和remove)。
不管怎样,它有一个问题。如果希望避免将来出现问题,必须在String大小写操作中指定Locale。因此,您将创建新的方法(get(String, Locale),…)。一切都更简单,更清晰的包装字符串:
public final class CaseInsensitiveString {
private final String s;
public CaseInsensitiveString(String s, Locale locale) {
this.s = s.toUpperCase(locale);
}
// equals, hashCode & toString, no need for memoizing hashCode
}
关于你对性能的担忧:过早的优化是万恶之源:)
一种方法是创建Apache Commons AbstractHashedMap类的自定义子类,覆盖散列和isEqualKeys方法来执行不区分大小写的散列和键的比较。(注:我自己从来没有试过……)
这避免了每次需要执行映射查找或更新时创建新对象的开销。常见的Map操作应该是O(1)…就像一个普通的HashMap。
如果您准备接受他们所做的实现选择,Apache Commons CaseInsensitiveMap将为您定制/专门化AbstractHashedMap。
但是如果O(logN)获取和放置操作是可接受的,那么带有不区分大小写字符串比较器的TreeMap是一个选项;例如,使用String.CASE_INSENSITIVE_ORDER。
如果您不介意每次执行put或get操作时创建一个新的临时String对象,那么Vishal的答案就很好。(不过,我注意到,如果你这样做,你就不会保留键的原始大小写…)
你可以使用CollationKey对象来代替字符串:
Locale locale = ...;
Collator collator = Collator.getInstance(locale);
collator.setStrength(Collator.SECONDARY); // Case-insensitive.
collator.setDecomposition(Collator.FULL_DECOMPOSITION);
CollationKey collationKey = collator.getCollationKey(stringKey);
hashMap.put(collationKey, value);
hashMap.get(collationKey);
使用排序器。忽略口音差异。
CollationKey API并不保证实现hashCode()和equals(),但实际上您将使用RuleBasedCollationKey,它实现了这些。如果你是偏执的,你可以使用TreeMap,它保证以O(log n)时间而不是O(1)的成本工作。