Java锯齿数组处理需分四层:第一层声明仅定行数,如int[][] data = new int[5][];第二层访问前须校验行存在及列索引有效;第三层遍历时内层上限为data[i].length;第四层高动态场景宜改用List<List<Integer>>。

Java 不规则二维数组(锯齿数组)的处理不能靠“套用规则数组思维”来解决,核心在于承认并尊重它的分层本质:外层数组管行数,每行子数组独立存在、长度自定、甚至可为空。逻辑分层设计,就是把这种物理结构映射为清晰的职责边界——每一层只做自己该做的事,不越界、不假设、不偷懒。
第一层:声明与初始化分离
外层数组声明只负责“划出多少行”,不分配任何具体数据空间。这一步纯粹是容器准备:
-
正确写法:
int[][] data = new int[5][];—— 创建含 5 个 null 引用的一维数组 -
禁止写法:
new int[5][3]或new int[][3]—— 编译失败或强制规则化 - 后续必须显式为每行赋值:
data[0] = new int[2]; data[1] = new int[7]; data[2] = new int[0]; - 推荐用空数组
new int[0]替代null,避免后续判空负担加重
第二层:访问前必校验存在性
每次取 data[i] 或 data[i][j] 前,必须分两步确认:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 行索引合法:
i >= 0 && i < data.length - 该行非空且列索引有效:
data[i] != null && j >= 0 && j < data[i].length - 切忌跳过判空直接调用
data[i].length,null 行会立即抛NullPointerException - 工具方法如
Arrays.toString(data[i])同样要求非 null,不可无条件使用
第三层:遍历按需动态定界
内层循环的上限不是常量,而是当前行的真实长度:
立即学习“Java免费学习笔记(深入)”;
- 行优先遍历中,内层条件必须是
j < data[i].length,绝不能写成j < data[0].length - 列优先遍历需先扫描求最大列宽:
int maxCols = Arrays.stream(data).filter(Objects::nonNull).mapToInt(a -> a.length).max().orElse(0); - 再对每一列
c,逐行检查:if (r < data.length && data[r] != null && c < data[r].length)
第四层:结构不稳定时考虑替代方案
当行数、列数频繁变动,或存在大量稀疏/动态增删需求时,原生数组维护成本陡增:
- 改用
List<List<Integer>>:天然支持 add/remove,get(i).size()稳定返回,无 null 行风险 - 适合场景:用户输入动态表格、解析不固定格式 CSV、树形结构扁平化存储等
- 注意权衡:失去随机访问效率和内存紧凑性,但换来逻辑清晰与容错能力

















