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 异常:
- 发现变量 'DD'-异常 'newId'
- 发现变量 'DU'-异常 'newId'
来自 PMD 文档:
- DU - Anomaly: A recently defined variable is undefined. These
anomalies may appear in normal source text.
- DD - Anomaly: A recently
defined variable is redefined. This is ominous but don’t have to be a
bug.
我尝试将 newId
变量移动到循环外,但随后出现错误:lambda 中使用的变量应该是最终的或有效的最终的。
如何重构我的代码以消除这些异常?或者我应该将这些警告抑制为误报?
您看到 DD 异常是因为当 if 条件的计算结果为 false 时,变量 newId
在 do { } 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 并在失败时抛出异常来解决无限循环问题。根据您的情况,您可能会选择不同的限制。
在下面的代码中,我创建了一个新 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 异常:
- 发现变量 'DD'-异常 'newId'
- 发现变量 'DU'-异常 'newId'
来自 PMD 文档:
- DU - Anomaly: A recently defined variable is undefined. These anomalies may appear in normal source text.
- DD - Anomaly: A recently defined variable is redefined. This is ominous but don’t have to be a bug.
我尝试将 newId
变量移动到循环外,但随后出现错误:lambda 中使用的变量应该是最终的或有效的最终的。
如何重构我的代码以消除这些异常?或者我应该将这些警告抑制为误报?
您看到 DD 异常是因为当 if 条件的计算结果为 false 时,变量 newId
在 do { } 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 并在失败时抛出异常来解决无限循环问题。根据您的情况,您可能会选择不同的限制。