可以做些什么来避免在使用记录时由于自动装箱而导致的隐藏错误



有时我会编写小脚本,以管理数据库中的记录或生成一些用于报告目的的数据。

大多数时候,我们使用Long类型作为用户实体的 ID。如果我执行以下操作:

List<Long> listOfLong = Arrays.asList(1L, 2L, 3L);
System.out.println(listOfLong.contains(2));

它返回false但为此:

System.out.println(integers.contains(2L));

它返回true.

我们不应该为这样的事情得到编译时错误吗?

您没有编译错误的原因是Collection<E>contains的签名定义为:

boolean contains(Object o)

没错,Object. 不是contains(<E> o).

(他们为什么这样定义它? 我知道这是为了与 Java 5 之前的 Java 版本兼容,当时集合类型不是通用的。 如果他们在Java 5中重新定义了contains方法,只允许<E>参数,那么它将破坏许多在早期版本的Java中工作的代码。

因此,就编译器而言,在List<Long>上调用contains时,Integer实例是合适的参数类型。

我们不应该为这样的事情得到编译时错误吗?

不。 它是有效的Java。

(如果你的意思是">

应该"的意思是"如果"会更好......那我同意。 但是contains这样定义是有原因的,没有回头路了。

可以做些什么来避免隐藏的错误

尝试使用静态代码分析器,如 FindBugs 或 PMD。 我不确定这些工具是否会检测到这个特定的错误,但它们可能会发现其他错误。

除此之外:

  • 更多测试。
  • 更改代码库以对 id 使用自定义类型。 一个不能自动装箱/取消装箱的。 (很多工作,治愈可能比疾病更糟糕......正如他们所说。

你问:

我们不应该为这样的事情得到编译时错误吗?

是的,我更喜欢这样,如果Java今天再次从头开始,也许会是这样。

如果这在我的代码中是一个严重的问题,我会为数字创建一个包装器,例如

class UserId {
public UserId(long id) { ... }
public long getId() { ... }
}

包含对对象类型参数使用等于方法的检查

boolean contains(Object o)

列表至少包含一个元素 e,以便(o==null ? e==null : o.equals(e))

如果您不记得/确定您将在使用前将值设置为 Long

你可以先投到长,你可以使用Long.valueOf

List<Long> listOfLong = Arrays.asList(1l, 2l, 3l);
System.out.println(listOfLong.contains(Long.valueOf(2)));

或者将值 2 作为方法参数发送,以便在方法签名中为 Long

public void myMethod(Long number) {
List<Long> listOfLong = Arrays.asList(1l, 2l, 3l);
System.out.println(listOfLong.contains(number));
}

要添加另一个正确的答案:虽然这不是编译错误(因为 JLS 中的任何内容都没有违反(,但您的工具可能会引发警告。Eclipse 会告诉你:

不太可能的参数类型int用于Collection<Long>上的contains(Object)

不太可能的参数类型long用于Collection<Integer>上的contains(Object)

相关内容

  • 没有找到相关文章

最新更新