Java递归函数计算递归次数出错

发布时间 2024-01-11 16:06:06作者: timseng

背景:构造组织架构树时,使用了递归填充子节点,为防止环状的错误数据导致递归无法结束,记录递归的次数,超过一定数量后终止递归

问题:用户记录递归次数的变量在节点跳转的时候被重新赋值,无法正确记录

 

public Depart genDepartTreeFromRoot() throws Exception {
    Depart root = Depart.builder().id("").name("").parentDepart(null).build();

    //防止部门数据有错误的环状结构导致死循环 最多填充1000000次
    fillDepartChildCount=0;
    fillDepartChildAndUserList(root,fillDepartChildCount);
    log.info("genDepartTreeFromRoot success  当前已填充子节点 {} 次 depart {}",fillDepartChildCount,root);

    return root;
  }
  public void fillDepartChildAndUserList(Depart depart,Integer fillDepartChildCount) throws Exception {
    if(fillDepartChildCount++>100000000){
      log.error("部门数据可能有错误的环状结构导致死循环  当前已填充子节点 {} 次 depart {}",fillDepartChildCount,depart);
      throw new Exception("部门数据可能有错误的环状结构导致死循环 当前已填充子节点"+fillDepartChildCount+"次");
    }

    List<User> userList = getDepartUserList(List.of(depart.getId()));
    depart.setUserList(userList);

    List<Depart> childList=getChildListLevel1(depart.getId());

    if(childList!=null && childList.size()>0){
      depart.setHasChild(true);
      depart.setChildren(childList);

      for (Depart departChild : childList) {
        departChild.setParentDepart(depart);
        fillDepartChildAndUserList(departChild,fillDepartChildCount);
      }
    }else{
      depart.setHasChild(false);
    }

  }

 解决:ChatGPT:

在 Java 中,基本类型(例如 int)是按值传递的。在你的代码中,fillDepartChildCount 是一个 Integer 对象,并不是基本类型。当你传递 fillDepartChildCountfillDepartChildAndUserList 方法时,传递的是对象引用的副本,而不是对象本身。这就导致了在递归调用过程中,虽然值被增加了,但是在上一级调用中的值并没有被更新。

为了解决这个问题,你可以使用一个封装了 fillDepartChildCount 的可变对象,比如一个数组或者一个包含计数值的对象。这样,在递归调用中,你修改的是数组或者对象内部的值,而不是传递的引用:

使用 AtomicInteger 类或者封装计数器的对象可以确保递归调用中正确地更新计数器的值,而不会出现因为传递引用导致值未更新的情况。

 

public Depart genDepartTreeFromRoot() throws Exception {
    Depart root = Depart.builder().id("").name("").parentDepart(null).build();

    // 使用可变对象封装计数器
    AtomicInteger fillDepartChildCount = new AtomicInteger(0);
    fillDepartChildAndUserList(root, fillDepartChildCount);
    log.info("genDepartTreeFromRoot success 当前已填充子节点 {} 次 depart {}", fillDepartChildCount.get(), root);

    return root;
}

public void fillDepartChildAndUserList(Depart depart, AtomicInteger fillDepartChildCount) throws Exception {
    // 在方法中使用 getAndIncrement() 方法来递增计数器
    if (fillDepartChildCount.getAndIncrement() > 100000000) {
        log.error("部门数据可能有错误的环状结构导致死循环 当前已填充子节点 {} 次 depart {}", fillDepartChildCount.get(), depart);
        throw new Exception("部门数据可能有错误的环状结构导致死循环 当前已填充子节点" + fillDepartChildCount.get() + "次");
    }

    // 其他部分保持不变
}