Java方法接收可变引用类型参数时会产生副作用,本质是值传递引用副本;应明确设计意图、防御性复制输入、返回新对象而非修改原对象。

Java 中方法接收可变引用类型参数(如 ArrayList、StringBuilder、自定义对象等)时,确实可能产生意外的副作用——外部传入的对象状态被内部修改,而调用方并不知情。这不是“引用传递”,而是“值传递引用副本”带来的自然结果。关键不在于阻止它发生,而在于**有意识地控制它是否发生、何时发生、如何隔离它**。
明确副作用是否属于设计意图
先判断:这个方法本就应该修改传入对象吗?
- 如果该方法语义就是“更新集合”(如
addItems(List<String> list, String... items)),那修改是合理且预期的; - 如果方法只是“读取并计算”(如
getMaxScore(Student[] students)),却顺手改了students[0].setScore(100),这就属于隐蔽副作用,应立即移除。
对输入做防御性复制(当不可变性是前提)
当方法逻辑要求“不改变原始数据”,但又需内部操作(比如排序、过滤、临时修改),就应在入口处复制一份:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 数组:用
Arrays.copyOf(originalArray, originalArray.length); -
List:用new ArrayList<>(originalList)或List.copyOf(originalList)(Java 10+,仅适用于不可变视图); - 自定义对象:若实现了
Cloneable,可用obj.clone();更推荐构造器复制或静态工厂方法,例如new Person(person.getName(), person.getAge())。
返回新对象而非复用原对象(函数式风格)
避免“就地修改”,转而返回新实例,让调用方决定是否替换:
立即学习“Java免费学习笔记(深入)”;
- 不要写:
list.sort(Comparator.naturalOrder()); return list; - return list.stream().sorted().collect(Collectors.toList());
- 类似地,
String操作天然如此(str.toUpperCase()返回新字符串),可作为范本参考。
文档与命名显式暴露行为
哪怕允许副作用,也要让使用者一眼看懂:
- 方法名体现可变性:用
mutateScores(...)、appendLog(...),而非模糊的process(...); - Javadoc 明确声明:
@param scores will be modified in-place; - 必要时加注解:如自定义
@Mutates或使用@Contract("_,_->this")(JetBrains 注解)辅助静态检查。

















