10

我最近被一个错误所困扰,其中我有一个带有 key type 的 Map Long,但我试图将它与 key type 一起使用String。我基本上有类似的东西:

Map<Long, Object> map;
...
String wrongType;
if (map.containsKey(wrongType)) {
    // Do something
} else {
    // Do something different
}

因为映射中的所有键都是 Long 类型,所以代码总是执行该else块。

由于containsKeyandget方法采用 type 参数Object,任何旧类型的对象都可以毫无怨言地接受。

我的困惑源于这样一个事实,即同一个实体在我们的系统中以两种不同的方式表示(有时是 a Long,有时是 a String);我不能轻易改变这一点。有什么方法可以在开发而不是测试期间发现这样的错误?也许是一个编译器标志或一些 Eclipse 选项,它们对于我应该使用什么类型的对象containsKeyget方法(以及它们在 中的类似物Set......)

4

3 回答 3

7

FindBugs 对此进行了测试:GC_UNRELATED_TYPES

在您的代码上运行 FindBugs 应该会揭示这一点,以及许多其他的东西;-)

于 2013-09-12T14:50:20.737 回答
4

你可以编写一个通用的实用方法来提供类型安全:

public static <T> boolean safeContainsKey(Map<T, ?> map, T key) {
  return map.containsKey(key);
}

public static <T, U> U safeGet(Map<T, U> map, T key) {
  return map.get(key);
}

现在,如果您传入错误的类型,您将收到编译时错误:

//These compile fine
boolean result1 = safeContainsKey(map, 12345l);
Object obj1 = safeGet(map, 12345l);

//These cause compilation errors
boolean result2 = safeContainsKey(map, "12345");
Object obj2 = safeGet(map, "12345");

您也可以实现自己的类型安全版本的Map接口,但这可能是矫枉过正。

就个人而言,我只是运行 Google 的CodePro Analytix,它将提供有用的类型安全警告。

于 2013-09-12T14:48:07.983 回答
3

Map方法get()contains()采取(而不是密钥的类型)的原因Object是它们早于泛型并且向后兼容,签名必须保持这种方式。

不幸的是,没有针对使用错误类型调用这些方法的编译器保护/警告。

于 2013-09-12T14:42:22.240 回答