FindBugs 插件 Eclipse 发现的错误
Bugs found by FindBugs plugin Eclipse
使用错误查找器插件,我发现了这个错误,但不明白为什么它在代码中被视为错误。有人知道这些并给我适当的解释吗?谢谢。
源代码 - https://drive.google.com/open?id=1gAyHFcdHBShV-9oC5G7GeOtCGf7bXoso;
Patient.java:17 Patient.generatePriority()使用Random的nextDouble方法生成一个随机整数;使用 nextInt 效率更高 [关注 (18),正常置信度]
public int generatePriority(){
Random random = new Random();
int n = 5;
return (int)(random.nextDouble()*n);
}
ExaminationRoom.java:25 ExaminationRoom 定义 equals 并使用 Object.hashCode() [Of Concern(16), Normal confidence]
public boolean equals(ExaminationRoom room){
if (this.getWaitingPatients().size() == room.getWaitingPatients().size()){
return true;
}
else {
return false;
}
}
ExaminationRoom.java:15 ExaminationRoom 定义 compareTo(ExaminationRoom) 并使用 Object.equals() [Of Concern(16), Normal confidence]
// Compares sizes of waiting lists
@Override
public int compareTo(ExaminationRoom o) {
if (this.getWaitingPatients().size() > o.getWaitingPatients().size()){
return 1;
}
else if (this.getWaitingPatients().size() < o.getWaitingPatients().size()){
return -1;
}
return 0;
}
Hospital.java:41 在 Hospital.initializeHospital() 中传递给新 java.util.GregorianCalendar(int, int, int) 的错误月份值 12 [Scary(7), Normal confidence]
doctors.add(new Doctor("Hermione", "Granger", new GregorianCalendar(1988, 12, 10), Specialty.PSY, room102));
Person.java:29 Return String.toLowerCase() 的值在 Person.getFullName() 中被忽略 [最可怕 (3),高可信度]
public String getFullName(){
firstName.toLowerCase();
Character.toUpperCase(firstName.charAt(0));
lastName.toLowerCase();
Character.toUpperCase(lastName.charAt(0));
return firstName + " " + lastName;
}
关于 "bug finder" 工具,首先要记住的是,它们通常只是指南。话虽如此:
classGregorianCalendar
从0开始算月数,即0为一月,11为十二月。 12 代表不存在的第 13 个月。由于该函数需要一个 int
,而您给它一个 int
,因此不会生成编译器错误,即使这肯定是一个错误。这篇文章很好地解释了升级的原因,并举例说明了如何使用新的 API:https://www.baeldung.com/java-8-date-time-intro
如有疑问,您可以随时查看文档。在这种情况下,class Calendar
(GregorianCalendar
扩展)delcares 一个静态常量 public static final int JANUARY = 0;
这证实了 1 月确实是 0
,但也表明我们可以在我们的代码中使用这个常量。您可能会发现 new GregorianCalendar(1988, Calendar.JANUARY, 10)
更具可读性。
您可能还想考虑切换到用于处理时间的更现代和标准的系统。 Java 8 时间库是 "new standard",绝对值得研究。
其次,String
在Java中是不可变的。这意味着一旦创建了 String
,它的值将永远无法更改。这可能与您的直觉相反,因为您可能已经看到如下代码:
String s = "hello";
s = s + " world";
但是,这不会修改 字符串s
。相反,s + " world"
创建一个新的 String
,并将其分配给变量 s
。
同样,s.toLowerCase()
不会改变 s
的内容,它只会生成一个新的 String
,您必须分配它。
你可能想要firstName = firstName.toLowerCase();
对于你的第一个例子,我没有立即想到 "bad",但如果你查看你的工具生成的消息,他们将第一个例子标记为 "Of Concern",但将其他(例如 string.toLowerCase()
示例)为 "Scary"/"Scariest"。虽然我不是特别熟悉这个工具,但我想这更像是一个 "Code Smell",而不是一个实际的错误。
如果你想让自己确信你的代码能正常工作,不妨看看单元测试。
- 不要每次都创建新的
Random
对象。
- 使用
random.nextInt(n)
.
- 在
ExaminationRoom
中定义一个hashCode
方法。
- 让您的
compareTo
方法 与 equals()
不一致可能是也可能不是。
- 使用
LocalDate
代替 GregorianCalendar
。
- 从
String.toLowerCase()
和 Character.toUpperCase()
中选取并使用 return 值。
- 将 SpotBugs 视为 FindBugs 的更新替代品。
详情
Random
每次需要时创建一个新的 Random
对象会产生较差的伪随机数,并且数字被重复的风险很高。在方法外部声明一个包含 Random
对象的静态变量,并在声明中对其进行初始化(Random
是线程安全的,因此您可以安全地执行此操作)。要绘制从 0 到 4 的伪随机数,请使用
int n = 5;
return random.nextInt(n);
它不仅效率更高(如 FindBugs 所说),而且我首先发现它更具可读性。
hashCode()
@Override
public int hashCode() {
return Objects.hash(getWaitingPatients());
}
compareTo()
您向我们展示的 equals
方法似乎与此处的 FindBugs 相矛盾。不过,它看起来确实有点可笑。如果两个候诊室有相同数量的候诊病人,它们是否被认为是相同的?请再考虑一下。如果您最终决定它们不相等但应该毫无歧视地分类到同一位置,则您的 compareTo
方法与 equals()
不一致。如果是这样,请插入一条说明这一事实的评论。如果您希望 FindBugs 在后续分析中不将此报告为错误,您有两个选择:
- 插入注释告诉 FindBugs 忽略“错误”。
- 创建一个包含这一点的 FindBugs 忽略 XML 文件。
对不起,我不记得每个细节了,但是你的搜索引擎应该会有帮助。
不要使用GregorianCalendar
GregorianCalendar
class 设计不佳且早已过时。我建议您从您的代码中删除它并使用 java.time 中的 LocalDate
,现代 Java 日期和时间 API,而不是
doctors.add(new Doctor("Hermione", "Granger", LocalDate.of(1988, Month.DECEMBER, 10), Specialty.PSY, room102));
String.toLowerCase()
这已经在其他答案中处理过了。将名称更改为首字母大写,其余字母小写并不像听起来那么简单。
firstName.toLowerCase();
Character.toUpperCase(firstName.charAt(0));
这两行中的第一行不修改字符串 firstName
因为字符串被设计为不可变的并且 toLowerCase()
到 return a new 全部字母小写的字符串(根据JVM默认locale的规则,容易混淆)。第二行也没有修改任何字符,因为 Java 是按值调用(查找),所以没有方法可以修改作为参数传递的变量。您甚至没有传递变量,而是来自不同方法的 return 值。还有 Character.toUpperCase()
returns 小写的 new 字符。
您需要做的是从这两个方法调用中提取值 returned,使用子字符串操作从名称的小写版本中删除第一个字母并连接大写-该字母的大小写版本与小写字符串的其余部分。如果它很复杂,我相信您的搜索引擎可以找到它在哪里以及如何完成的示例。
题外话:在强迫 Dr. Jack McNeil 写成 Mcneil 和 Dr. Ludwig von Saulsbourg 写成 Von saulsbourg.[= 之前,您可能需要三思。 49=]
SpotBugs
只是听说而已,自己没有去查过。 FindBugs 的源代码已被名为 SpotBugs 的项目接管。他们说 SpotBugs 的开发比 FindBugs 更积极。所以你可以考虑转行。我自己在日常工作中是一个快乐的 SpotBugs 用户。
链接
- What issues should be considered when overriding equals and hashCode in Java?
- Documentation of
Comparable
解释 compareTo()
与 equals()
不一致的含义以及如何处理。
- Oracle tutorial: Date Time 解释如何使用 java.time.
- Chicago Hope 将 Jack McNeil 列为整形外科医生。
- Dr. Jack 在剧组中提到 Ludwig von Saulsbourg 博士。
- SpotBugs
使用错误查找器插件,我发现了这个错误,但不明白为什么它在代码中被视为错误。有人知道这些并给我适当的解释吗?谢谢。
源代码 - https://drive.google.com/open?id=1gAyHFcdHBShV-9oC5G7GeOtCGf7bXoso;
Patient.java:17 Patient.generatePriority()使用Random的nextDouble方法生成一个随机整数;使用 nextInt 效率更高 [关注 (18),正常置信度]
public int generatePriority(){
Random random = new Random();
int n = 5;
return (int)(random.nextDouble()*n);
}
ExaminationRoom.java:25 ExaminationRoom 定义 equals 并使用 Object.hashCode() [Of Concern(16), Normal confidence]
public boolean equals(ExaminationRoom room){
if (this.getWaitingPatients().size() == room.getWaitingPatients().size()){
return true;
}
else {
return false;
}
}
ExaminationRoom.java:15 ExaminationRoom 定义 compareTo(ExaminationRoom) 并使用 Object.equals() [Of Concern(16), Normal confidence]
// Compares sizes of waiting lists
@Override
public int compareTo(ExaminationRoom o) {
if (this.getWaitingPatients().size() > o.getWaitingPatients().size()){
return 1;
}
else if (this.getWaitingPatients().size() < o.getWaitingPatients().size()){
return -1;
}
return 0;
}
Hospital.java:41 在 Hospital.initializeHospital() 中传递给新 java.util.GregorianCalendar(int, int, int) 的错误月份值 12 [Scary(7), Normal confidence]
doctors.add(new Doctor("Hermione", "Granger", new GregorianCalendar(1988, 12, 10), Specialty.PSY, room102));
Person.java:29 Return String.toLowerCase() 的值在 Person.getFullName() 中被忽略 [最可怕 (3),高可信度]
public String getFullName(){
firstName.toLowerCase();
Character.toUpperCase(firstName.charAt(0));
lastName.toLowerCase();
Character.toUpperCase(lastName.charAt(0));
return firstName + " " + lastName;
}
关于 "bug finder" 工具,首先要记住的是,它们通常只是指南。话虽如此:
classGregorianCalendar
从0开始算月数,即0为一月,11为十二月。 12 代表不存在的第 13 个月。由于该函数需要一个 int
,而您给它一个 int
,因此不会生成编译器错误,即使这肯定是一个错误。这篇文章很好地解释了升级的原因,并举例说明了如何使用新的 API:https://www.baeldung.com/java-8-date-time-intro
如有疑问,您可以随时查看文档。在这种情况下,class Calendar
(GregorianCalendar
扩展)delcares 一个静态常量 public static final int JANUARY = 0;
这证实了 1 月确实是 0
,但也表明我们可以在我们的代码中使用这个常量。您可能会发现 new GregorianCalendar(1988, Calendar.JANUARY, 10)
更具可读性。
您可能还想考虑切换到用于处理时间的更现代和标准的系统。 Java 8 时间库是 "new standard",绝对值得研究。
其次,String
在Java中是不可变的。这意味着一旦创建了 String
,它的值将永远无法更改。这可能与您的直觉相反,因为您可能已经看到如下代码:
String s = "hello";
s = s + " world";
但是,这不会修改 字符串s
。相反,s + " world"
创建一个新的 String
,并将其分配给变量 s
。
同样,s.toLowerCase()
不会改变 s
的内容,它只会生成一个新的 String
,您必须分配它。
你可能想要firstName = firstName.toLowerCase();
对于你的第一个例子,我没有立即想到 "bad",但如果你查看你的工具生成的消息,他们将第一个例子标记为 "Of Concern",但将其他(例如 string.toLowerCase()
示例)为 "Scary"/"Scariest"。虽然我不是特别熟悉这个工具,但我想这更像是一个 "Code Smell",而不是一个实际的错误。
如果你想让自己确信你的代码能正常工作,不妨看看单元测试。
- 不要每次都创建新的
Random
对象。 - 使用
random.nextInt(n)
. - 在
ExaminationRoom
中定义一个hashCode
方法。 - 让您的
compareTo
方法 与equals()
不一致可能是也可能不是。 - 使用
LocalDate
代替GregorianCalendar
。 - 从
String.toLowerCase()
和Character.toUpperCase()
中选取并使用 return 值。 - 将 SpotBugs 视为 FindBugs 的更新替代品。
详情
Random
每次需要时创建一个新的 Random
对象会产生较差的伪随机数,并且数字被重复的风险很高。在方法外部声明一个包含 Random
对象的静态变量,并在声明中对其进行初始化(Random
是线程安全的,因此您可以安全地执行此操作)。要绘制从 0 到 4 的伪随机数,请使用
int n = 5;
return random.nextInt(n);
它不仅效率更高(如 FindBugs 所说),而且我首先发现它更具可读性。
hashCode()
@Override
public int hashCode() {
return Objects.hash(getWaitingPatients());
}
compareTo()
您向我们展示的 equals
方法似乎与此处的 FindBugs 相矛盾。不过,它看起来确实有点可笑。如果两个候诊室有相同数量的候诊病人,它们是否被认为是相同的?请再考虑一下。如果您最终决定它们不相等但应该毫无歧视地分类到同一位置,则您的 compareTo
方法与 equals()
不一致。如果是这样,请插入一条说明这一事实的评论。如果您希望 FindBugs 在后续分析中不将此报告为错误,您有两个选择:
- 插入注释告诉 FindBugs 忽略“错误”。
- 创建一个包含这一点的 FindBugs 忽略 XML 文件。
对不起,我不记得每个细节了,但是你的搜索引擎应该会有帮助。
不要使用GregorianCalendar
GregorianCalendar
class 设计不佳且早已过时。我建议您从您的代码中删除它并使用 java.time 中的 LocalDate
,现代 Java 日期和时间 API,而不是
doctors.add(new Doctor("Hermione", "Granger", LocalDate.of(1988, Month.DECEMBER, 10), Specialty.PSY, room102));
String.toLowerCase()
这已经在其他答案中处理过了。将名称更改为首字母大写,其余字母小写并不像听起来那么简单。
firstName.toLowerCase();
Character.toUpperCase(firstName.charAt(0));
这两行中的第一行不修改字符串 firstName
因为字符串被设计为不可变的并且 toLowerCase()
到 return a new 全部字母小写的字符串(根据JVM默认locale的规则,容易混淆)。第二行也没有修改任何字符,因为 Java 是按值调用(查找),所以没有方法可以修改作为参数传递的变量。您甚至没有传递变量,而是来自不同方法的 return 值。还有 Character.toUpperCase()
returns 小写的 new 字符。
您需要做的是从这两个方法调用中提取值 returned,使用子字符串操作从名称的小写版本中删除第一个字母并连接大写-该字母的大小写版本与小写字符串的其余部分。如果它很复杂,我相信您的搜索引擎可以找到它在哪里以及如何完成的示例。
题外话:在强迫 Dr. Jack McNeil 写成 Mcneil 和 Dr. Ludwig von Saulsbourg 写成 Von saulsbourg.[= 之前,您可能需要三思。 49=]
SpotBugs
只是听说而已,自己没有去查过。 FindBugs 的源代码已被名为 SpotBugs 的项目接管。他们说 SpotBugs 的开发比 FindBugs 更积极。所以你可以考虑转行。我自己在日常工作中是一个快乐的 SpotBugs 用户。
链接
- What issues should be considered when overriding equals and hashCode in Java?
- Documentation of
Comparable
解释compareTo()
与equals()
不一致的含义以及如何处理。 - Oracle tutorial: Date Time 解释如何使用 java.time.
- Chicago Hope 将 Jack McNeil 列为整形外科医生。
- Dr. Jack 在剧组中提到 Ludwig von Saulsbourg 博士。
- SpotBugs