拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Lombok 使用@With 注释

Lombok 使用@With 注释

白鹭 - 2021-12-21 2165 0 2

一、介绍

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 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *