来自 PMD 的 Java 流 while 循环异常警告

Posted

技术标签:

【中文标题】来自 PMD 的 Java 流 while 循环异常警告【英文标题】:Java stream while loop anomaly warnings from PMD 【发布时间】:2020-10-08 05:56:51 【问题描述】:

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

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 异常:

发现变量“newId”的“DD”异常 发现变量“newId”的“DU”异常

来自 PMD 文档:

    DU - 异常:最近定义的变量未定义。这些 异常可能出现在正常的源文本中。 DD - 异常:A 最近 定义的变量被重新定义。这是不祥之兆,但不一定是 错误。

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

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

【问题讨论】:

与问题无关,但您不应生成这样的 ID。您拥有的项目越多,所需的时间就越长(生成 n 个 ID 需要 O(n^2) 步)。您应该使用 UUID,这在技术上并不能避免 ID 冲突,但它们太不可能了,所以没关系。 @***soft 我知道,不幸的是,这是客户端的要求之一——保持向后兼容性。我更喜欢使用 UUID,我就是不能...... 【参考方案1】:

您看到了 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()));
    

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

【讨论】:

以上是关于来自 PMD 的 Java 流 while 循环异常警告的主要内容,如果未能解决你的问题,请参考以下文章

来自 pmd:DataflowAnomalyAnalysis sslContext 的 Java UR-anomaly 和 DR-anomaly

Java代码PMD抱怨Cyclomatic Complexity,20

关于IO流中下while循环句解释:while ((len=fr.read(c))!=-1)

pmd静态代码分析

java基础-控制流语句

IT兄弟连 Java语法教程 流程控制语句 循环结构语句3