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

来自PMD的Java流while循环异常警告,java,java-stream,static-analysis,pmd,Java,Java Stream,Static Analysis,Pmd,在以下代码中,我创建了一个新ID,检查它是否存在,如果它是唯一的,则返回它: private String generateNewId(List<Item> items) { do { String newId = ... // generateNewId from another method if (items.stream.noneMatch(i -> i.getId().equals(newId))) {

在以下代码中,我创建了一个新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);
}
private String generateNewId(列表项){
做{
字符串newId=…//generateNewId来自另一个方法
if(items.stream.noneMatch(i->i.getId().equals(newId))){
返回newId;
}
}虽然(正确);
}
但是,我发现PMD异常:

  • 发现变量“newId”的“DD”-异常
  • 发现变量“newId”的“DU”异常
从PMD文档:

  • DU-异常:最近定义的变量未定义。这些 正常源文本中可能出现异常
  • DD-异常:一种新的异常 定义的变量被重新定义。这是一个不祥的预兆,但不一定是一个灾难 臭虫
  • 我尝试将
    newId
    变量移出循环,但后来我得到了错误:lambda中使用的变量应该是final或实际上是final


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

    您正在看到DD异常,因为当if条件计算为false时,变量
    newId
    do{}while(true)
    循环中被重新定义

    然而,我认为DU异常是假阳性。在这种情况下,
    newId
    始终至少使用一次:

    • 如果项目列表为空,则返回
      newId
    • 如果项目列表不为空,则
      newId
      用于关闭
      nonMatch
    但这是PMD无法理解的,因为它不知道
    noneMatch
    的语义。如果将
    noneMatch
    替换为
    anyMatch
    ,则这将是一个真正的DU异常

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

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

    private String generateNewId(列表项){
    return Stream.generate(this::getRandomId)
    .限额(100)
    .filter(id->isNew(id,items))
    .findAny()
    .orelsetrow(()->new NoSuchElementException(“未能生成唯一id”);
    }
    私有字符串getRandomId(){
    返回“4”;//由公平掷骰选择。
    //保证是随机的。
    }
    私有布尔值isNew(字符串id,列表项){
    返回items.stream().noneMatch(item->id.equals(item.getId());
    }
    

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

    您正在看到DD异常,因为当if条件计算为false时,变量
    newId
    do{}while(true)
    循环中被重新定义

    然而,我认为DU异常是假阳性。在这种情况下,
    newId
    始终至少使用一次:

    • 如果项目列表为空,则返回
      newId
    • 如果项目列表不为空,则
      newId
      用于关闭
      nonMatch
    但这是PMD无法理解的,因为它不知道
    noneMatch
    的语义。如果将
    noneMatch
    替换为
    anyMatch
    ,则这将是一个真正的DU异常

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

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

    private String generateNewId(列表项){
    return Stream.generate(this::getRandomId)
    .限额(100)
    .filter(id->isNew(id,items))
    .findAny()
    .orelsetrow(()->new NoSuchElementException(“未能生成唯一id”);
    }
    私有字符串getRandomId(){
    返回“4”;//由公平掷骰选择。
    //保证是随机的。
    }
    私有布尔值isNew(字符串id,列表项){
    返回items.stream().noneMatch(item->id.equals(item.getId());
    }
    

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

    与问题无关,但您不应该生成这样的ID。您拥有的项目越多,所需时间越长(生成n个ID需要O(n^2)个步骤)。您应该使用UUID,从技术上讲,UUID并不能避免ID冲突,但它们太不可能了,这无关紧要。@Clashsoft我知道,不幸的是,这是客户端的一个要求-保持向后兼容性。我更喜欢使用UUID,我只是不能…与问题无关,但你不应该生成这样的ID。您拥有的项目越多,所需时间越长(生成n个ID需要O(n^2)个步骤)。您应该使用UUID,从技术上讲,UUID并不能避免ID冲突,但它们太不可能了,这无关紧要。@Clashsoft我知道,不幸的是,这是客户端的一个要求-保持向后兼容性。我更喜欢使用UUID,我就是不能。。。