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 CalendarGregorianCalendar 扩展)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",而不是一个实际的错误。

如果你想让自己确信你的代码能正常工作,不妨看看单元测试。

  1. 不要每次都创建新的 Random 对象。
  2. 使用random.nextInt(n).
  3. ExaminationRoom中定义一个hashCode方法。
  4. 让您的 compareTo 方法 equals() 不一致可能是也可能不是。
  5. 使用 LocalDate 代替 GregorianCalendar
  6. String.toLowerCase()Character.toUpperCase() 中选取并使用 return 值。
  7. 将 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 在后续分析中不将此报告为错误,您有两个选择:

  1. 插入注释告诉 FindBugs 忽略“错误”。
  2. 创建一个包含这一点的 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 用户。

链接