Java中ArrayList在被方法设为非空后长度异常归零的问题排查
问题排查与解决方案
首先,我先帮你梳理下代码里的关键问题,以及导致validResources在placement中变为空的可能原因:
1. 先看最明显的代码逻辑问题
你的detection方法里,checkTime初始值是0,所以循环条件for (int i = 1; i < checkTime+1; i++)等价于i < 1,而i从1开始,这个循环根本不会执行。按照当前代码,detection会直接走到最后返回false,但你说它返回了true,这说明要么你贴代码时漏写了checkTime的赋值逻辑(比如应该是checkTime = buildingTemplate.length或者模板数组的长度),要么这是笔误。这个点必须先修正,否则validResources根本不会被填充。
2. 导致validResources在placement中为空的核心原因
validResources被声明为private static,这意味着它是一个全局唯一的集合实例,整个应用中所有代码都共享它。这种设计很容易导致意外修改:
- 如果在
detection返回true(此时集合有元素)和调用placement之间,有其他代码路径调用了validResources.clear()(比如compare方法的else分支,或者其他地方的直接调用),集合就会被清空。 - 如果是多线程环境,另一个线程同时调用
detection或compare,也可能触发clear操作,直接清空集合。 - 哪怕是单线程,若你在
detection返回true后,又不小心调用了其他会修改这个集合的方法,同样会导致数据丢失。
3. 修复建议与优化方案
方案一:先调试追踪集合变化
在所有修改validResources的地方添加日志,明确集合的变化时机:
// 在match方法添加元素时 validResources.add(toBeChecked); System.out.println("[DEBUG] Added element, size: " + validResources.size() + " | Thread: " + Thread.currentThread().getName()); // 在compare方法清空时 validResources.clear(); System.out.println("[DEBUG] Cleared collection, size: " + validResources.size() + " | Thread: " + Thread.currentThread().getName()); // 在detection返回true前 System.out.println("[DEBUG] detection returning true, size: " + validResources.size()); return true; // 在placement方法开头 System.out.println("[DEBUG] placement start, size: " + validResources.size());
通过日志你能清晰看到,是不是在detection和placement之间,集合被意外修改了。
方案二:替换静态集合为局部变量(推荐)
静态集合的全局状态是这类问题的根源,最好的解决方式是把validResources改成局部变量,通过方法参数传递,避免全局共享:
// 修改detection方法,返回有效资源集合 public static List<TownResource> detection(int row, int col, TownResource[][] rArray, ResourceEnum[][][] bT, BuildingEnum buildingType) { List<TownResource> validResources = new ArrayList<>(); int checkTime = bT.length; // 假设bT是模板数组,设置正确的循环次数 int patternIndex = 0; try { for (int i = 0; i < checkTime; i++) { if (compare(row, col, rArray, bT[patternIndex], buildingType, validResources)) { for (TownResource tr : validResources) { tr.setScannedBuilding(buildingType); } System.out.println("Size at compare: " + validResources.size()); return validResources; } } } catch (ArrayIndexOutOfBoundsException e){ e.printStackTrace(); // 打印异常方便排查 } return Collections.emptyList(); } // 修改compare方法,传入局部集合 private static boolean compare(int row, int col, TownResource[][] rArray, ResourceEnum[][] buildingTemplate, BuildingEnum buildingType, List<TownResource> validResources) { validResources.clear(); // 每次检查前清空,避免残留 for (int r = 0; r < buildingTemplate.length; r++) { for (int c = 0; c < buildingTemplate[r].length; c++) { if (match(rArray[row+r][col+c], buildingTemplate[r][c], validResources)) { // 调试日志可保留 } else { validResources.clear(); return false; } } } return true; } // 修改match方法,传入局部集合 private static boolean match(TownResource toBeChecked, ResourceEnum checker, List<TownResource> validResources) { if (checker == ResourceEnum.NONE) { return true; } else if (toBeChecked.getResource() == checker) { validResources.add(toBeChecked); return true; } return false; } // 调用逻辑修改 List<TownResource> valid = detection(row, col, rArray, bT, buildingType); if (!valid.isEmpty()) { placement(rArray, bArray, building, valid); } // 修改placement方法,接收局部集合 public static void placement(TownResource[][] rArray, Building[][] bArray, BuildingEnum building, List<TownResource> validResources) { System.out.println(validResources.size()); for (TownResource tr : validResources) { System.out.println("Is this statement firing?"); System.out.println(tr.getResource()); tr.setResource(ResourceEnum.NONE); } }
这种方式彻底消除了全局静态集合带来的意外修改风险,代码也更健壮、易维护。
内容的提问来源于stack exchange,提问作者QuantumBlink
相关产品推荐
相关产品推荐

