一、介绍
Lombok 是一个库,可帮助我们在写 Java 应用程序时显著作用样板代码。
在本教程中,我们将看到如何使用此制作仅更改一个属性的库不创建对象的副本。
2. 适用
当使用拒绝设置器的不发光对象时,我们可能需要一个与当前对像的对象,但只有一个不同的属性。这可以使用 Lombok 的@With
注释来实现:
public class User { private final String username; private final String emailAddress; @With private final boolean isAuthenticated; //getters, constructors }
上面的注释在后台生成以下内容:
public class User { private final String username; private final String emailAddress; private final boolean isAuthenticated; //getters, constructors public User withAuthenticated(boolean isAuthenticated) { return this.isAuthenticated == isAuthenticated ? this : new User(this.username, this.emailAddress, isAuthenticated); } }
然后我们可以使用上面的方法来创建原始对象的衍生版本:
User immutableUser = new User("testuser", "test@1ju.org", false); User authenticatedUser = immutableUser.withAuthenticated(true); assertNotSame(immutableUser, authenticatedUser); assertFalse(immutableUser.isAuthenticated()); assertTrue(authenticatedUser.isAuthenticated());
此外,我们可以选择注释整个类,这有所有属性withX()
方法。
三、要求
要@With
注释,需要提供一个全参数构造。从上面的例子我们可以构成我们,生成的方法需要这个来创建原始对象的克隆。
我们可以使用Lombok的的自己@AllArgsConstructor
或@Value
注释来满足此要求。或者,我们也可以手动提供此构造函数,同时确保类中非静态属性的顺序与构造函数的顺序相匹配。
我们应该记住,如果在静态字段上使用@With
**注释,则什么也不做。这是因为静态属性不被视为对象状态的一部分。此外,Lombok的展示跳过会$
符号开头和结尾的字段**的方法生成。
4. 高级用
让我们研究一下使用这个注释时的一些高级场景。
4.1.抽像类
我们可以在抽像类的字段上@With
public abstract class Device { private final String serial; @With private final boolean isInspected; //getters, constructor }
但是,我们需要为生成的withInspected()
方法提供一个实现。因为龙目岛不知道我们抽像类的具体实现来创建它的克隆:
public class KioskDevice extends Device { @Override public Device withInspected(boolean isInspected) { return new KioskDevice(getSerial(), isInspected); } //getters, constructor }
4.2. 固有约定
原来,Lombok 将跳过以$
符号概括的大小。但是,如果以文字形式出现,则它是标题写的,最后,with
是生成方法的前缀。
或者,如果该范围以下的线路概要,则只能with
作为生成方法的预判:
public class Holder { @With private String variableA; @With private String _variableB; @With private String $variableC; //getters, constructor excluding $variableC }
可知上面的代码,我们只能看到前面的两个变量是他们生成的withX()
Holder value = new Holder("a", "b"); Holder valueModifiedA = value.withVariableA("mod-a"); Holder valueModifiedB = value.with_variableB("mod-b"); // Holder valueModifiedC = value.with$VariableC("mod-c"); not possible
4.3.方法生成的异常
我们应该注意,除了以$
符号开头的领域之外,如果我们的类中已经存在withX()
方法,龙目岛将不会生成它:
public class Stock { @With private String sku; @With private int stockCount; //prevents another withSku() method from being generated public Stock withSku(String sku) { return new Stock("mod-" + sku, stockCount); } //constructor }
在上述场景中,不会生成新的withSku()
方法。
此外,Lombok在以下场景中会****跳过方法生成:
public class Stock { @With private String sku; private int stockCount; //also prevents another withSku() method from being generated public Stock withSKU(String... sku) { return sku == null || sku.length == 0 ? new Stock("unknown", stockCount) : new Stock("mod-" + sku[0], stockCount); } //constructor }
我们可以注意到上面的withSKU()
基本,如果出现以下情况,龙目岛将跳过方法生成:
与生成的方法名存在相同的方法(忽略大小写)
已有方法与的方法具有相同数量的生成参数(包括var-args)
4.4.生成方法的空验证
与其他龙目岛注释类似,我们可以@With
注释生成的方法进行null
@With @AllArgsConstructor public class ImprovedUser { @NonNull private final String username; @NonNull private final String emailAddress; }
Lombok 需要我们生成以下代码以及需要的null
检查:
public ImprovedUser withUsername(@NonNull String username) { if (username == null) { throw new NullPointerException("username is marked non-null but is null"); } else { return this.username == username ? this : new ImprovedUser(username, this.emailAddress); } } public ImprovedUser withEmailAddress(@NonNull String emailAddress) { if (emailAddress == null) { throw new NullPointerException("emailAddress is marked non-null but is null"); } else { return this.emailAddress == emailAddress ? this : new ImprovedUser(this.username, emailAddress); } }
5. 结论
在本文中,我们已经看到了如何使用 Lombok 的@With
注释来生成具有特定变化的特定对象的克隆。
我们还了解到此方法生成的实际工作方式和时间,以及如何进行其他验证(例如null
检查)来增强它。
0 评论