概述
Project Lombok 是一个工具,它帮助我们在 Java 源代码中减少冗余任务。本教程将解释如何在 Lombok 中通过声明局部 val
和 var
变量来推断类型。
2. 声明 val
和 var
变量在 Lombok 中
Lombok 提供了智能能力来避免样板代码,例如,它会隐藏领域模型对象的 getter 和 setter。Builder 注解是另一个有趣的功能,它有助于正确实现 Builder 模式。
接下来的章节我们将关注 Lombok 的一个功能,即不指定类型的定义局部变量。我们将使用 Lombok 的 val
和 var
类型来声明变量,从而减少源代码中的额外行。
val
在版本 0.10 中引入。使用val
时,Lombok 将变量声明为final
,并在初始化后自动推断类型。因此,初始化表达式是必需的。var
在版本 1.16.20 中引入。与val
类似,它也会根据初始化表达式推断类型,但主要区别在于变量不会被声明为final
。因此,允许进一步的赋值,但应遵循在声明变量时指定的类型。
3. 在 Lombok 中实现 val
和 var
示例
3.1. 依赖项
为了实现示例,我们只需在 pom.xml
中添加 Lombok 依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
您可以在此处检查最新的可用版本:这里。
3.2. val
变量声明
首先,我们导入 Lombok 的 val
类型:
import lombok.val;
然后,我们使用 val
声明不同的局部变量。例如,我们可以从一个简单的 String
开始:
public Class name() {
val name = "name";
System.out.println("Name: " + name);
return name.getClass();
}
Lombok 自动生成如下基本的 Java 代码:
final java.lang.String name = "name";
接着,创建一个 Integer
:
public Class age() {
val age = Integer.valueOf(30);
System.out.println("Age: " + age);
return age.getClass();
}
如您所见,Lombok 会生成正确的类型:
final java.lang.Integer age = Integer.valueOf(30);
我们还可以声明一个 List
:
public Class listOf() {
val agenda = new ArrayList<String>();
agenda.add("Day 1");
System.out.println("Agenda: " + agenda);
return agenda.getClass();
}
Lombok 不仅推断了 List
类型,还推断了其中元素的类型:
final java.util.ArrayList<java.lang.String> agenda = new ArrayList<String>();
现在,让我们创建一个 Map
:
public Class mapOf() {
val books = new HashMap<Integer, String>();
books.put(1, "Book 1");
books.put(2, "Book 2");
System.out.println("Books:");
for (val entry : books.entrySet()) {
System.out.printf("- %d. %s\n", entry.getKey(), entry.getValue());
}
return books.getClass();
}
同样,Lombok 会推断出适当的类型:
final java.util.HashMap<java.lang.Integer, java.lang.String> books = new HashMap<Integer, String>();
// ...
for (final java.util.Map.Entry<java.lang.Integer, java.lang.String> entry : books.entrySet()) {
// ...
}
可以看到 Lombok 会声明为 final
的正确类型。因此,如果我们尝试修改变量名,由于 val
的 final
性质,构建会失败:
name = "newName";
[12,9] cannot assign a value to final variable name
接下来,我们将运行一些测试以验证 Lombok 是否生成了正确的类型:
ValExample val = new ValExample();
assertThat(val.name()).isEqualTo(String.class);
assertThat(val.age()).isEqualTo(Integer.class);
assertThat(val.listOf()).isEqualTo(ArrayList.class);
assertThat(val.mapOf()).isEqualTo(HashMap.class);
最后,我们可以在控制台输出中看到具有特定类型的对象:
Name: name
Age: 30
Agenda: [Day 1]
Books:
- 1. Book 1
- 2. Book 2
3.3. var
变量声明
var
声明与 val
类似,但变量不是 final
的:
import lombok.var;
var name = "name";
name = "newName";
var age = Integer.valueOf(30);
age = 35;
var agenda = new ArrayList<String>();
agenda.add("Day 1");
agenda = new ArrayList<String>(Arrays.asList("Day 2"));
var books = new HashMap<Integer, String>();
books.put(1, "Book 1");
books.put(2, "Book 2");
books = new HashMap<Integer, String>();
books.put(3, "Book 3");
books.put(4, "Book 4");
让我们看看生成的基本 Java 代码:
var name = "name";
var age = Integer.valueOf(30);
var agenda = new ArrayList<String>();
var books = new HashMap<Integer, String>();
这是因为 Java 10 支持使用初始化表达式推断本地变量的类型,称为 类型推断。然而,在使用它时,我们需要考虑一些 限制。
由于声明的变量不是 final
,我们可以进行进一步的赋值。不过,对象必须符合初始化表达式中推断的适当类型。
如果尝试分配不同的类型,编译时会出现错误:
books = new ArrayList<String>();
[37,17] incompatible types: java.util.ArrayList<java.lang.String> cannot be converted to java.util.HashMap<java.lang.Integer,java.lang.String>
让我们稍微调整测试,并检查新的赋值:
VarExample varExample = new VarExample();
assertThat(varExample.name()).isEqualTo("newName");
assertThat(varExample.age()).isEqualTo(35);
assertThat("Day 2").isIn(varExample.listOf());
assertThat(varExample.mapOf()).containsValue("Book 3");
最后,控制台输出与上一节有所不同:
Name: newName
Age: 35
Agenda: [Day 2]
Books:
- 3. Book 3
- 4. Book 4
4. 复合类型
有时,我们需要使用复合类型作为初始化表达式:
val compound = isArray ? new ArrayList<String>() : new HashSet<String>();
在上述片段中,赋值取决于布尔值,且最常见的是继承自的超类被推断。
Lombok 将类型分配为 AbstractCollection
,如基本代码所示:
final java.util.AbstractCollection<java.lang.String> compound = isArray ? new ArrayList<String>() : new HashSet<String>();
在诸如 null
值这样的模糊情况下,推断为 Object
类。
5. 配置键
Lombok 允许在整个项目中在一个文件中配置功能。因此,可以在一个地方包含项目的全局指令和设置。
有时,作为项目开发标准的一部分,我们可能希望限制对 Lombok 的 var
和 val
的使用。如果有人意外地使用它们,我们可能希望在编译时发出警告。
对于这种情况,我们可以通过在 lombok.config
文件中包含以下内容,将 var
或 val
的任何使用标记为警告或错误:
lombok.var.flagUsage = error
lombok.val.flagUsage = warning
我们将在整个项目中收到关于非法使用 var
的错误:
[12,13] Use of var is flagged according to lombok configuration.
同样,我们也会收到关于使用 val
的警告消息:
ValExample.java:18: warning: Use of val is flagged according to lombok configuration.
val age = Integer.valueOf(30);
6. 总结
在这篇文章中,我们展示了如何在 Lombok 中使用不指定类型的定义局部变量。此外,我们了解了声明 val
和 var
变量的细节。
我们还演示了如何处理复合类型的局部变量声明。
如往常一样,代码可在 GitHub 上找到。