Java不规则二维数组是“数组的数组”,每行独立且长度可变;创建需两步(声明+逐行分配),静态初始化最安全,动态初始化须显式赋值每行;访问前须校验i范围、arr[i]非null、j范围;遍历仅推荐双层传统for并嵌套校验。

Java 不规则二维数组不是“特殊数组”,而是对“数组的数组”这一本质的自然延伸——每行独立、长度可变、引用自由。它在处理分组数据、稀疏结构、动态表单、多级嵌套响应等场景中,比规则数组更贴合真实业务逻辑。关键不在“怎么写”,而在“怎么防错”和“怎么用得稳”。
创建:必须两步走,不能跳过“逐行分配”
不规则数组声明后,外层数组只存引用,所有子数组默认为 null。直接访问未初始化的行会立即抛 NullPointerException。
- 静态初始化最安全:用花括号直接写出各行,长度由元素个数决定
int[][] groups = {{101}, {202, 203, 204}, {}, {305, 306}}; - 动态初始化需显式赋值每行:
String[][] records = new String[4][];<br>records[0] = new String[]{"A", "B"};<br>records[1] = new String[]{"C"};<br>records[2] = new String[0]; // 空数组,非 null,后续可安全取 .length<br>records[3] = null; // 合法但需遍历时单独处理 - 避免留空行:若某行逻辑上无数据,优先用
new int[0]而非null,统一判空逻辑
访问与修改:每次下标前,先问三件事
访问 arr[i][j] 前,必须确认:
- i 是否在 [0, arr.length) 范围内?
-
arr[i] 是否不为 null?(否则
.length或[j]都会崩) -
j 是否在 [0, arr[i].length) 范围内?(不能套用
arr[0].length)
封装成工具方法更可靠:
static Integer get(int[][] arr, int i, int j) {<br> if (i < 0 || i >= arr.length || arr[i] == null || j < 0 || j >= arr[i].length) return null;<br> return arr[i][j];<br>}
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
遍历:传统 for 是唯一推荐方式
增强 for(for-each)无法获取行列索引,且遇到 null 行时会直接中断。必须用双层传统 for,并严格嵌套校验:
- 外层循环控制行:
for (int i = 0; i - 进入内层前判空:
if (arr[i] != null) - 内层循环用该行真实长度:
for (int j = 0; j
示例(带空行容错):
for (int i = 0; i < data.length; i++) {<br> if (data[i] != null) {<br> for (int j = 0; j < data[i].length; j++) {<br> process(data[i][j]);<br> }<br> }<br>}
替代建议:何时该放弃原生数组?
当出现以下情况时,优先考虑 List<List<T>>:
- 行或列需要频繁增删(如实时追加日志分组)
- 数据来源是 JSON 或数据库结果集,结构高度不确定
- 团队协作中希望减少空指针风险,提升可读性
对比示例:
List<List<String>> table = new ArrayList<>();<br>table.add(Arrays.asList("name", "age")); // 第一行<br>table.add(Arrays.asList("Alice", "30")); // 第二行<br>// 访问:if (i < table.size() && j < table.get(i).size()) { ... }集合天然规避
null 行问题,size() 总是安全可调用。

















