system.arraycopy需手动校验:先判src/dest非null,再判srcpos/destpos/length≥0,最后用减法验证边界(如srcpos > src.length - length)防溢出,推荐封装为safecopy工具方法。

System.arraycopy 本身不做任何参数校验,所有边界和空值检查都必须由调用方显式完成。写得松散容易抛异常,写得太啰嗦又影响可读性。高效写法的核心是:**一次判断覆盖全部必要条件,不重复计算,不遗漏 null 和越界场景**。
关键校验项必须合并判断
五个参数中,真正需要联合验证的是三项:
- src 和 dest 非 null:任一为 null 直接抛 NullPointerException
- srcPos、destPos、length 均 ≥ 0:负数索引或负长度非法
- srcPos + length ≤ src.length 且 destPos + length ≤ dest.length:这是最易出错的整数溢出点
推荐把这三组条件写在一条 if 中,避免多次分支跳转,也防止 length 很大时 srcPos + length 溢出 int(不过实际业务中 length 一般来自数组 length,极少超限)。
校验顺序要兼顾性能与语义清晰
先判 null,再判负值,最后算边界——这样既符合直觉,又能尽早失败:
- null 判定最快,且一旦失败无需后续计算
- 负值检查成本极低,比加法还轻
- 边界加法虽快,但应放在最后,避免无谓执行
示例(int[] 场景):
if (src == null || dest == null || srcPos srcPos > src.length - length || destPos > dest.length - length) {throw new IndexOutOfBoundsException();
}
用减法代替加法防溢出(进阶技巧)
虽然日常几乎不会遇到 srcPos + length 溢出,但严格来说,srcPos > src.length - length 比 srcPos + length > src.length 更安全——它用减法规避了 int 加法溢出风险。JDK 自身源码也采用这种写法。对 dest 同理。
- 优点:逻辑等价,但数值更稳定
- 注意:
src.length - length在 length == 0 时等于 src.length,合法;length > src.length 时结果为负,不等式自然成立,触发异常
封装成工具方法提升复用性
重复校验代码分散在各处,既冗余又难维护。建议封装一个带校验的静态方法,例如:
public static void safeCopy(int[] src, int srcPos, int[] dest, int destPos, int length) {if (src == null || dest == null || srcPos srcPos > src.length - length || destPos > dest.length - length) {
throw new IndexOutOfBoundsException("Invalid arraycopy args");
}
System.arraycopy(src, srcPos, dest, destPos, length);
}
类型可重载支持 byte[]、long[] 等,也可泛型化(用 Object[] + 类型擦除,配合 Array.newInstance 构建新数组)。











