如何检查地图中的密钥而不管情况如何?

我想知道HashMap中是否存在特定的键,所以我使用的是containsKey(key)方法。 但它区分大小写,即如果有一个带有Name的键并且我正在搜索名称,则它不会返回true。 那么有什么方法我可以知道而不用打扰钥匙的情况?

谢谢

不是传统的地图。

“abc”是来自“ABC”的不同字符串,它们的哈希码是不同的,并且它们的equals()方法将相对于彼此返回false。

最简单的解决方案是在插入/检查之前简单地将所有输入转换为大写(或小写)。 您甚至可以编写自己的Map包装器,以确保一致性。

如果你想保持所提供的密钥的大小写,但是使用不区分大小写的比较,你可以考虑使用TreeMap并提供你自己的比较器,它将比较不区分大小写。 但是,在走这条路之前要认真思考,因为你最终遇到一些不可调和的不一致 – 如果有人调用map.put("abc", 1)然后map.put("ABC", 2) ,那么密钥存储的是什么情况在地图上? 你能说得有意义吗? 如果有人用标准的例如HashMap包装您的地图,您会失去function吗? 或者,如果有人碰巧正在迭代你的密钥集,并使用equals()进行自己的快速“包含”检查,你会得到不一致的结果吗? 还会有很多其他类似的案例。 请注意,这样做违反了Map的契约 (因为键的相等性是根据键上的equals()方法定义的 )所以它在任何意义上都是不可行的。

维护严格的大写映射容易使用和维护,并且具有实际上是合法的Map实现的优点。

您可以将TreeMap与自定义的不区分大小写的Comparator (使用String.compareToIgnoreCase() )一起使用

例如:

 Map map = new TreeMap(CaseInsensitiveComparator.INSTANCE); class CaseInsensitiveComparator implements Comparator { public static final CaseInsensitiveComparator INSTANCE = new CaseInsensitiveComparator(); public int compare(String first, String second) { // some null checks return first.compareToIgnoreCase(second); } } 

更新:似乎String已将此Comparator定义为常量。

使用由String#CASE_INSENSITIVE_ORDER构造的TreeMap

 Map map = new TreeMap(String.CASE_INSENSITIVE_ORDER); map.put("FOO", "FOO"); System.out.println(map.get("foo")); // FOO System.out.println(map.get("Foo")); // FOO System.out.println(map.get("FOO")); // FOO 

Apache commons中有一个CaseInsensitiveMap类

http://commons.apache.org/collections/

要保留Map不变量,您可以创建自己的键。 实现合理的hashCode / equals ,你很高兴:

 final class CaseInsensitive { private final String s; private final Local lc; public CaseInsensitive (String s, Locale lc) { if (lc == null) throw new NullPointerException(); this.s = s; this.lc = lc; } private s(){ return s == null ? null : s.toUpperCase(lc); } @Override public int hashCode(){ String u = s(); return (u == null) ? 0 : u.hashCode(); } @Override public boolean equals(Object o){ if (!getClass().isInstance(o)) return false; String ts = s(), os = ((CaseInsensitive)other).s(); if (ts == null) return os == null; return ts.equals(os); } } // Usage: Map map = ...; map.put(new CaseInsensitive("hax", Locale.ROOT), 1337); assert map.get(new CaseInsensitive("HAX", Locale.ROOT) == 1337; 

注意:并非全世界的每个人都同意什么是大写的 – 一个着名的例子是土耳其语中的“i”的大写版本是“İ”而不是“我”。

Map使用equalshashCode来测试密钥相等性,并且不能为String覆盖这些。 你可以做的是定义你自己的Key类,它包含一个字符串值,但以不区分大小写的方式实现equalshashCode

最简单的方法是在插入按键并查找按键时自行折叠按键。 即

 map.put(key.toLowerCase(), value); 

 map.get(key.toLowerCase()); 

如果你想自动完成这个,你可以将例如HashMap子类化为自己的类。

创建自己的字符串类包装器,实现equals和hashcode,使用它作为hashmap中的键:

  class MyStringKey { private String string; public String getString() { return string; } public void setString(String string) { this.string = string; } public boolean equals(Object o) { return o instanceof MyStringKey && this.equalsIgnoreCase(((MyStringKey)o).getString()); } public boolean hashCode() { return string.toLowerCase().hashcode(); //STRING and string may not have same hashcode } } 

试图提出符合您的问题要求的答案“不用打扰钥匙的情况” ……

如果您在许多地方添加到地图中,这个答案可能会很乏味。 在我的例子中,它只发生在用户创建一个新角色时(在我的游戏中)。 这是我如何处理这个:

 boolean caseInsensitiveMatch = false; for (Map.Entry entry : MyServer.allCharacterMap.entrySet()) { if (entry.getKey().toLowerCase().equals(charNameToCreate.toLowerCase())){ caseInsensitiveMatch = true; break; } } 

当然这需要在我的大型ConcurrentHashMap中循环,但对我有用。