Java 流式传输来自 PMD 的循环异常警告

Java stream while loop anomaly warnings from PMD

在下面的代码中,我创建了一个新 ID,检查它是否存在,return 如果它是唯一的:

private String generateNewId(List<Item> items) {
    do {
        String newId = ... // generateNewId from another method
        if (items.stream.noneMatch(i -> i.getId().equals(newId))) {
            return newId;
        }
    } while(true);
}

但是,我遇到了 PMD 异常:

来自 PMD 文档:

  1. DU - Anomaly: A recently defined variable is undefined. These anomalies may appear in normal source text.
  2. DD - Anomaly: A recently defined variable is redefined. This is ominous but don’t have to be a bug.

我尝试将 newId 变量移动到循环外,但随后出现错误:lambda 中使用的变量应该是最终的或有效的最终的

如何重构我的代码以消除这些异常?或者我应该将这些警告抑制为误报?

您看到 DD 异常是因为当 if 条件的计算结果为 false 时,变量 newIddo { } while(true) 循环中被重新定义。

然而,我认为 DU 异常是误报。在这种情况下 newId 总是至少使用一次:

  • 如果项目列表为空,则返回 newId
  • 如果项目列表不为空,则在 nonMatch
  • 的闭包中使用 newId

但这是 PMD 无法理解的,因为它不知道 noneMatch 的语义。如果您将 noneMatch 替换为 anyMatch,那么这将是一个真正的 DU 异常。

DD 和 DU 异常通常很难修复,因为它们在更高层次上指出了设计问题。在这种情况下,问题不直接在于变量 newId 本身,而是使用 do { } while(true) 这可能会导致无限循环,因为您忽略了无法生成新的唯一 ID 的情况。

解决此问题的一种方法是解决此问题:

    private String generateNewId(List<Item> items) {
        return Stream.generate(this::getRandomId)
                     .limit(100)
                     .filter(id -> isNew(id, items))
                     .findAny()
                     .orElseThrow(() -> new NoSuchElementException("Failed to generate unique id."));
    }

    private String getRandomId() {
        return "4";  // chosen by fair dice roll.
                     // guaranteed to be random.
    }

    private boolean isNew(String id, List<Item> items) {
        return items.stream().noneMatch(item -> id.equals(item.getId()));
    }

此解决方案通过最多尝试生成 100 次新 ID 并在失败时抛出异常来解决无限循环问题。根据您的情况,您可能会选择不同的限制。