首页 > 编程语言 >Java递归函数计算递归次数出错

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

时间:2024-01-11 16:14:32浏览次数:33  
标签:depart 递归 递归函数 Java Depart root 节点 fillDepartChildCount

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

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

 

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() + "次");
    }

    // 其他部分保持不变
}

 

标签:depart,递归,递归函数,Java,Depart,root,节点,fillDepartChildCount
From: https://www.cnblogs.com/timseng/p/17958789

相关文章

  • JavaScript 中的事件循环
    事件循环是JavaScript运行时环境的核心组件。它负责调度和执行异步任务。事件循环通过持续监视两个队列来工作:调用堆栈和事件队列。调用堆栈是一种堆栈(LIFO)数据结构,存储当前正在执行的函数(存储代码执行期间创建的执行上下文)。WebAPI是异步操作(setTimeout、获取请求、promise)......
  • java使用 template模板ftl 含有图片的生成数据
    点击查看代码/***Base64编码.*/publicstaticStringbase64Encode(byte[]input){BASE64Encoderencoder=newBASE64Encoder();returnencoder.encode(input);}@OverridepublicvoidprintStudentRxdjb(StudentRxdj......
  • java上传图片or头像
     走upload方法进行文件的保存,第一个参数为上传文件的类型,头像or照片  第一步检查是否可以上传,是否是jpg,png等类型第二步根据日期,文件名,uuid等生成文件名称。第三步将文件保存到服务器最后return的是一个文件的相对地址,根据subDir和fileName+文件名返回的相对路径,比如p......
  • java~类型的逆变和协变
    在Java中,泛型的逆变(contravariance)和协变(covariance)是涉及到泛型类型转换时的两个重要概念。协变(Covariance)协变指的是子类型对象可以赋值给父类型引用的情况。在泛型中,协变表示如果B是A的子类,那么List<B>就是List<A>的子类。这意味着你可以将List<B>赋值给List<A>......
  • java实体类中给引用类型对象直接赋值报错记录
    实体类TestModel,Attachment类也是一个实体类packagecom.sinochem.it.model;importcom.alibaba.fastjson.JSONObject;publicclassTestModel{intage;Stringname;JSONObjectobj;Attachmentattachment;publicAttachmentgetAttachment(){......
  • 记使用Arthas定位并解决Java应用死锁问题
    背景在一次生产环境部署后,我们的JavaWeb应用开始表现出严重的性能下降。用户报告说网页响应变得非常慢,有时甚至完全无响应。初步检查服务器资源和应用日志未发现明显的问题,我们怀疑可能是应用内部出现了死锁。引入Arthas为了不影响生产环境运行,我们决定使用Arthas进行问题诊断。Ar......
  • 大话 JavaScript(Speaking JavaScript):第三十一章到第三十三章
    第三十一章:模块系统和包管理器原文:31.ModuleSystemsandPackageManagers译者:飞龙协议:CCBY-NC-SA4.0JavaScript没有内置模块支持,但社区已经创建了令人印象深刻的解决方法。要管理模块,可以使用所谓的包管理器,它们处理发现、安装、依赖管理等。模块系统JavaScript模......
  • 大话 JavaScript(Speaking JavaScript):第二十一章到第二十五章
    第二十一章:数学原文:21.Math译者:飞龙协议:CCBY-NC-SA4.0Math对象用作多个数学函数的命名空间。本章提供了一个概述。数学属性Math的属性如下:Math.E欧拉常数(e)Math.LN22的自然对数Math.LN1010的自然对数Math.LOG2Ee的底数2对数Math.LOG10Ee的十进制对数Ma......
  • [转]JAVA使用LocalDate获取当前日期所在季度的开始日期和结束日期
    原文地址:JAVA使用LocalDate获取当前日期所在季度的开始日期和结束日期-yvioo-博客园需要使用jdk1.8及以上  /***获取当前日期所在季度的开始日期和结束日期*季度一年四季,第一季度:1月-3月,第二季度:4月-6月,第三季度:7月-9月,第四季度:10月-12月......
  • 大话 JavaScript(Speaking JavaScript):第二十六章到第三十章
    第四部分:提示,工具和库原文:IV.Tips,Tools,andLibraries译者:飞龙协议:CCBY-NC-SA4.0本部分提供了使用JavaScript的技巧(最佳实践,高级技术和学习资源),并描述了一些重要的工具和库。第二十六章:元代码风格指南原文:26.AMetaCodeStyleGuide译者:飞龙协议:CCBY-NC-SA......