You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JUnit断言错误排查:大输入量下预期异常未抛出问题咨询

问题分析与解决方案

为什么大输入未触发预期异常?

你的JUnit测试预期输入256、10000这类值时抛出异常,但当前代码没有触发,核心原因是输入大小的校验逻辑缺失:

当前buildTriangle方法仅校验了输入非空、无null值、大小远小于Integer.MAX_VALUE,但没有检查输入的元素数量是否刚好能填满你定义的锯齿三角结构。

从你的示例和countSize方法的逻辑来看,这个三角的元素总数是有固定规律的:当行数为rows时,总元素数是1+2+3+...+(rows-1)+1 = (rows-1)*rows/2 +1(比如rows=4时,总数是7,刚好匹配你的示例输入)。如果输入的元素数不等于这个固定值,就无法完整构建三角,此时应该抛出异常,但你的代码没有这个判断。

修复方案

修改countSize方法,让它同时返回三角能容纳的最大元素总数,然后在buildTriangle中校验输入大小是否等于这个总数:

private static int[] countSize(int listSize) { 
    int rows = 0; 
    int columns = 0;
    int maxElements = 0;
    int prevTotal = 1;
    int step = 0;
    // 替换原来晦涩的for循环为可读性更强的while循环
    while (prevTotal + step <= listSize) {
        maxElements = prevTotal + step;
        prevTotal = maxElements;
        step++;
        rows++;
    }
    columns = 2 * rows - 1; 
    return new int[] { rows, columns, maxElements }; 
}

然后在buildTriangle中添加校验:

int[] sizes = countSize(list.size());
// 校验输入大小是否刚好匹配三角所需元素数
if (sizes[2] != list.size()) {
    throw new myException("Input size does not match the required number of elements for the triangle");
}

这样当输入256、10000这类不匹配三角元素总数的值时,就会抛出异常,符合JUnit测试的预期。


代码评审建议

1. 异常处理优化

  • 命名规范:myException不符合Java驼峰命名法,应改为MyException。
  • 保留异常上下文:buildPyramid方法中捕获异常后直接抛出新的空参数异常,丢失了原异常的信息和栈轨迹,不利于调试。建议修改为:
    public int[][] buildPyramid(List<Integer> input) {
        try {
            return buildTriangle(input);
        } catch (MyException e) {
            // 保留原异常信息和栈轨迹
            throw new MyException("Failed to build pyramid", e);
        }
    }
    
  • 冗余校验:list.size()<Integer.MAX_VALUE - 8这个条件几乎不会触发(Integer.MAX_VALUE是2147483647,减8后仍远大于常规输入大小),可以移除。

2. 代码可读性提升

  • 变量命名:countSize中的x、y含义模糊,改为prevTotal、step这类有意义的名字(如上面修复方案中的写法)。
  • 循环写法:原来的for循环for(int x=1, y=0; x+y<=listSize; x=x+y, y++, rows++);过于晦涩,换成while循环更易理解。
  • 代码格式:单行for循环建议加上大括号,比如:
    for (int y=0; y<sizes[1]; y++) {
        System.out.print("\t" + resArray[x][y] + " ");
    }
    
  • 集合排序简化:workList.addAll(list); Collections.sort(workList);可以简化为:
    List<Integer> sortedList = list.stream().sorted().collect(Collectors.toList());
    
    (记得导入java.util.stream.Collectors)

3. 逻辑完整性

  • 填充逻辑补全:你代码中的//...sort logic...部分缺失,需要按照示例的结构填充排序后的元素到二维数组中。参考示例的位置规律:
    • 第i行(0-based,非最后一行):从columns/2 - i位置开始,每隔2个位置放一个元素,共i+1个元素。
    • 最后一行:仅在第0个位置放最后一个元素。
      示例填充代码片段:
    int elementIndex = 0;
    int mid = sizes[1] / 2;
    for (int i = 0; i < sizes[0]; i++) {
        if (i == sizes[0] - 1) {
            // 最后一行,仅填充第一个位置
            resArray[i][0] = sortedList.get(elementIndex);
            elementIndex++;
        } else {
            int startPos = mid - i;
            for (int j = 0; j < i + 1; j++) {
                resArray[i][startPos + j * 2] = sortedList.get(elementIndex);
                elementIndex++;
            }
        }
    }
    

4. 性能优化

  • 空值检查效率:list.contains(null)的时间复杂度是O(n),如果输入list很大,会影响性能。可以在排序或遍历填充时顺便检查空值,比如:
    List<Integer> sortedList = list.stream()
        .peek(num -> {
            if (num == null) {
                throw new MyException("Input list contains null elements");
            }
        })
        .sorted()
        .collect(Collectors.toList());
    
    这样可以避免单独遍历一次list。

内容的提问来源于stack exchange,提问作者freekickr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:03:26