如何在Java Lambda表达式中“固化”值?构建器场景问题
如何让每个Lambda表达式拥有独立的乘数函数?
问题代码
@FunctionalInterface interface Callable { Integer multiply(Integer by); } class Builder { private Integer multiplier; public Builder multiplyBy(Integer multiplier) { this.multiplier= multiplier; return this; } public Callable build() { return (value) -> value * multiplier; // 如何"固化"当前值? } } // 调用代码 Builder builder = new Builder(); Callable multiplierBy3 = builder.multiplyBy(3).build(); Callable multiplierBy6 = builder.multiplyBy(6).build(); multiplierBy3.multiply(10); // 预期返回30,实际返回60 multiplierBy6.multiply(10); // 返回60,符合预期
问题原因
Lambda表达式捕获的是Builder实例中multiplier的引用,而非当前值。第二次调用multiplyBy(6)修改了同一个Builder实例的multiplier值,导致之前创建的multiplierBy3也会使用更新后的数值。
解决方案
方案1:捕获局部变量固化当前值
在build方法中,先将当前multiplier赋值给一个局部变量,让Lambda捕获这个局部变量(局部变量默认是等效final的,不会被后续修改):
public Callable build() { Integer currentMultiplier = this.multiplier; // 复制当前值到局部变量 return (value) -> value * currentMultiplier; }
方案2:让Builder成为不可变类,每次生成新实例
将Builder设计为不可变类,每次设置参数时返回新的Builder实例,从根源避免状态共享:
@FunctionalInterface interface Callable { Integer multiply(Integer by); } class Builder { private final Integer multiplier; // 用final确保不可变 // 私有构造器,只能通过静态方法创建实例 private Builder(Integer multiplier) { this.multiplier = multiplier; } public static Builder multiplyBy(Integer multiplier) { return new Builder(multiplier); } public Callable build() { return (value) -> value * multiplier; } } // 调用方式调整为: Callable multiplierBy3 = Builder.multiplyBy(3).build(); Callable multiplierBy6 = Builder.multiplyBy(6).build();
方案3:修改multiplyBy方法返回新实例
如果保留原有Builder的结构,修改multiplyBy方法,每次调用时创建新的Builder实例并设置参数,而非修改当前实例:
public Builder multiplyBy(Integer multiplier) { Builder newBuilder = new Builder(); newBuilder.multiplier = multiplier; return newBuilder; }
说明
方案1是最轻量化的修改,仅调整build方法即可;方案2从设计层面避免了状态共享,更符合不可变对象的设计原则,适合需要多次复用Builder的场景;方案3则是在原有API基础上做最小调整,保持链式调用的同时避免状态污染。
内容的提问来源于stack exchange,提问作者colorgreen
相关产品推荐
相关产品推荐

