在使用记录时,可以做什么来避免由于自动装箱而导致的隐藏错误
what can be done to avoid following hidden mistake due to autoboxing while working with Records
有时我会编写一些小脚本,以管理数据库中的记录或生成一些用于报告目的的数据。
大多数时候我们使用 Long
类型作为用户实体的 ID。如果我执行以下操作:
List<Long> listOfLong = Arrays.asList(1L, 2L, 3L);
System.out.println(listOfLong.contains(2));
它 returns false
但为此:
System.out.println(integers.contains(2L));
它returns true
.
我们不应该得到这样的编译时错误吗?
contains 使用 equals 方法检查对象类型参数
boolean contains(Object o)
list contains at least one element e such that (o==null ? e==null : o.equals(e))
如果你不这样做 remember/sure 你将在使用它之前将值设置为 Long
可以先投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));
}
您问的是:
Shouldn't we get a compile time error for such thing?
是的,如果 Java 今天再次从头开始,我更愿意那样做。
如果这在我的代码中是一个严重的问题,我会为该数字创建一个包装器,例如
class UserId {
public UserId(long id) { ... }
public long getId() { ... }
}
你没有编译错误的原因是 Collection<E>
中 contains
的签名定义为:
boolean contains(Object o)
没错,Object
。不是 contains(<E> o)
。
(他们为什么这样定义它?我知道这是为了与 Java 5 之前的 Java 版本兼容,当时集合类型不是通用的。如果他们重新定义了Java 5 中的 contains
方法只允许 <E>
个参数,它会破坏很多在早期版本 Java 中工作的代码。)
因此,就编译器而言,在 List<Long>
.
上调用 contains
时,Integer
实例是合适的参数类型
Shouldn't we get a compile time error for such thing ?
没有。有效 Java。
(如果你的意思是 "should" 在 "it would be better if" 的意义上......那么我同意。但是 contains
被这样定义是有原因的,并且没有回头路.)
What can be done to avoid the hidden mistake
尝试使用 FindBugs 或 PMD 等静态代码分析器。我不确定这些工具是否会检测到这个特定错误,但它们可能会发现其他错误。
除此之外:
- 更多测试。
- 更改您的代码库以使用自定义类型的 ID。一个不能自动装箱/拆箱的。 (很多工作,治愈可能比疾病更糟糕......正如他们所说。)
补充另一个正确的答案:虽然这不是编译错误(因为没有违反 JLS 中的任何内容),但您的工具可能会发出警告。 Eclipse 会告诉你:
Unlikely argument type int
for contains(Object)
on a Collection<Long>
Unlikely argument type long
for contains(Object)
on a Collection<Integer>
有时我会编写一些小脚本,以管理数据库中的记录或生成一些用于报告目的的数据。
大多数时候我们使用 Long
类型作为用户实体的 ID。如果我执行以下操作:
List<Long> listOfLong = Arrays.asList(1L, 2L, 3L);
System.out.println(listOfLong.contains(2));
它 returns false
但为此:
System.out.println(integers.contains(2L));
它returns true
.
我们不应该得到这样的编译时错误吗?
contains 使用 equals 方法检查对象类型参数
boolean contains(Object o)
list contains at least one element e such that
(o==null ? e==null : o.equals(e))
如果你不这样做 remember/sure 你将在使用它之前将值设置为 Long
可以先投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));
}
您问的是:
Shouldn't we get a compile time error for such thing?
是的,如果 Java 今天再次从头开始,我更愿意那样做。
如果这在我的代码中是一个严重的问题,我会为该数字创建一个包装器,例如
class UserId {
public UserId(long id) { ... }
public long getId() { ... }
}
你没有编译错误的原因是 Collection<E>
中 contains
的签名定义为:
boolean contains(Object o)
没错,Object
。不是 contains(<E> o)
。
(他们为什么这样定义它?我知道这是为了与 Java 5 之前的 Java 版本兼容,当时集合类型不是通用的。如果他们重新定义了Java 5 中的 contains
方法只允许 <E>
个参数,它会破坏很多在早期版本 Java 中工作的代码。)
因此,就编译器而言,在 List<Long>
.
contains
时,Integer
实例是合适的参数类型
Shouldn't we get a compile time error for such thing ?
没有。有效 Java。
(如果你的意思是 "should" 在 "it would be better if" 的意义上......那么我同意。但是 contains
被这样定义是有原因的,并且没有回头路.)
What can be done to avoid the hidden mistake
尝试使用 FindBugs 或 PMD 等静态代码分析器。我不确定这些工具是否会检测到这个特定错误,但它们可能会发现其他错误。
除此之外:
- 更多测试。
- 更改您的代码库以使用自定义类型的 ID。一个不能自动装箱/拆箱的。 (很多工作,治愈可能比疾病更糟糕......正如他们所说。)
补充另一个正确的答案:虽然这不是编译错误(因为没有违反 JLS 中的任何内容),但您的工具可能会发出警告。 Eclipse 会告诉你:
Unlikely argument type
int
forcontains(Object)
on aCollection<Long>
Unlikely argument type
long
forcontains(Object)
on aCollection<Integer>