专业的JAVA编程教程与资源

网站首页 > java教程 正文

一文通关Lombok插件-java编码又爱又恨的大杀器

temp10 2025-02-15 17:26:17 java教程 8 ℃ 0 评论

Lombok是一个Java库,它能通过注解的方式来减少代码中的样板代码(如getter、setter、构造函数等),让代码更加简洁。

一文通关Lombok插件-java编码又爱又恨的大杀器


1.安装Lombok

- 如果你使用Maven构建项目,需要在 pom.xml 文件中添加Lombok依赖:

xml

org.projectlombok

lombok

1.18.28

provided

- 若是Gradle构建项目,在 build.gradle 文件中添加:

groovy

compileOnly 'org.projectlombok:lombok:1.18.28'

annotationProcessor 'org.projectlombok:lombok:1.18.28'

同时,要确保你的IDE安装了Lombok插件。以IntelliJ IDEA为例,在插件市场搜索Lombok并安装,安装后重启IDE。


2.Lombok常用注解

@Data

- 功能:这个注解会自动为类生成以下方法:

- 所有属性的 getter 和 setter 方法。

- toString() 方法,用于打印对象的属性信息。

- equals() 和 hashCode() 方法,用于比较和哈希操作。


举个栗子:

import lombok.Data;
@Data
class Student {
??? private String name;
??? private int age;
}
public class Main {
??? public static void main(String[] args) {
??????? Student student = new Student();
??????? student.setName("小明");
??????? student.setAge(18);
??????? System.out.println(student);
??????? // 输出内容类似:Student(name=小明, age=18)
??? }
}

@Getter和@Setter

- 功能:

- @Getter 为类中的属性生成 getter 方法。

- @Setter 为类中的属性生成 setter 方法。可以指定访问级别,如 @Setter(AccessLevel.PROTECTED) 。



举个栗子:

import lombok.Getter;
import lombok.Setter;
class Book {
??? @Getter
??? @Setter
??? private String title;
}
public class Main {
??? public static void main(String[] args) {
??????? Book book = new Book();
??????? book.setTitle("Java编程思想");
??????? System.out.println(book.getTitle());
??? }
}


@NoArgsConstructor

- 功能:生成一个无参构造函数。如果类中的属性有 final 修饰,并且没有初始化,会导致编译错误,因为 final 属性必须在构造函数中初始化。


举个栗子:

import lombok.NoArgsConstructor;
@NoArgsConstructor
class User {
??? private String username;
}
public class Main {
??? public static void main(String[] args) {
??????? User user = new User();
??? }
}


@AllArgsConstructor

- 功能:生成一个包含所有参数的构造函数。参数的顺序和类中属性声明的顺序一致。



举个栗子:

import lombok.AllArgsConstructor;
@AllArgsConstructor
class Order {
??? private int id;
??? private String productName;
}
public class Main {
??? public static void main(String[] args) {
??????? Order order = new Order(1, "手机");
??? }
}

@Builder

- 功能:使用这个注解可以让类支持建造者(Builder)模式。可以方便地创建复杂对象。



举个栗子:

import lombok.Builder;
import lombok.ToString;
@Builder
@ToString
class Computer {
??? private String cpu;
??? private int memory;
}
public class Main {
??? public static void main(String[] args) {
??????? Computer computer = Computer.builder()
?????????????? .cpu("Intel i7")
?????????????? .memory(16)
?????????????? .build();
??????? System.out.println(computer);
??? }
}


@Slf4j

Lombok提供的一个注解,用于简化日志记录。它会自动为类添加一个名为 log 的日志记录器变量,这个变量的类型通常是 org.slf4j.Logger ,可以方便地在类中记录各种级别的日志信息,如 DEBUG 、 INFO 、 WARN 、 ERROR 等。

使用步骤和示例

- 添加依赖:

- 首先,除了Lombok依赖外,需要在项目中添加 slf4j - api 依赖和对应的日志实现(如 log4j 、 logback 等)。以 logback 为例,在Maven项目的 pom.xml 文件中添加如下依赖:

xml

org.slf4j

slf4j - api

1.7.36

ch.qos.logback

logback - classic

1.2.11

- 在类中使用:

- 当在一个Java类中添加 @Slf4j 注解后,Lombok会自动生成日志记录器。


举个栗子:

import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MyClass {
??? public void doSomething() {
??????? log.info("开始执行doSomething方法");
??????? try {
??????????? // 这里可以是一些可能会抛出异常的代码
??????????? int result = 1 / 0;
??????? } catch (Exception e) {
??????????? log.error("在执行doSomething方法时出错", e);
??????? }
??? }
}


- 在这个示例中, MyClass 类被标注了 @Slf4j 。在 doSomething 方法中,首先使用 log.info 记录了方法开始执行的信息。然后,当出现异常(这里是除零异常)时,使用 log.error 记录了错误信息,并且将异常对象 e 作为参数传递,这样可以在日志中记录详细的异常堆栈信息。


@SneakyThrows

- 功能:这个注解用于简化异常抛出的代码。通常在Java中,如果一个方法可能会抛出已检查异常(Checked Exception),需要在方法签名中声明或者在方法内部使用 try - catch 块处理。 @SneakyThrows 允许将已检查异常包装成运行时异常(Runtime Exception)抛出,从而简化代码。



举个栗子:

import lombok.SneakyThrows;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

class FileReader {
??? @SneakyThrows(FileNotFoundException.class)
??? public void readFile() {
??????? FileInputStream fis = new FileInputStream("example.txt");
??????? // 这里可以继续对文件输入流进行操作
??? }
}


在这个例子中, readFile 方法可能会抛出 FileNotFoundException ,

使用 @SneakyThrows 注解后,就不需要在方法签名中声明这个异常,也不用写 try - catch 块,使得代码更加简洁。不过这种方式要谨慎使用,因为将检查异常转换为运行时异常可能会掩盖一些潜在的错误处理需求。

@Cleanup

- 功能: @Cleanup 注解用于自动清理资源,主要针对实现了 java.io.Closeable 接口(如文件流、数据库连接等)的资源。当变量的作用域结束时,Lombok会自动调用其 close 方法来释放资源。


举个栗子:

import lombok.Cleanup;
import java.io.FileOutputStream;
import java.io.IOException;

class FileWriter {
??? public void writeToFile() throws IOException {
??????? @Cleanup FileOutputStream fos = new FileOutputStream("output.txt");
??????? fos.write("Hello World".getBytes());
??? }
}

在这个示例中, FileOutputStream 对象 fos 被标注了 @Cleanup 。当 writeToFile 方法执行完毕后,Lombok会自动调用 fos.close() 方法,确保文件输出流被正确关闭,避免资源泄漏。

3.实验性功能注解


Lombok的部分实验性功能,需要更加谨慎使用。


1. @Accessors链式调用- 功能描述:用于改变Lombok生成的 getter 和 setter 方法的行为,提供了几个配置选项。

fluent 选项设置为 true 时,生成的 getter 和 setter 方法会省略 get 和 set 前缀,使方法调用更流畅;

chain 选项设为 true 时, setter 方法会返回对象本身,便于链式调用;

prefix 选项可指定字段的前缀,Lombok在生成方法时会依据此前缀来处理。


举个栗子:

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(fluent = true, chain = true)
class Car {
??? private String brand;
??? private int year;
}
public class Main {
??? public static void main(String[] args) {
??????? Car car = new Car().brand("Toyota").year(2022);
??????? System.out.println(car.brand());
??? }
}

在这个示例中, Car 类使用了 @Accessors 注解, fluent = true 使得 brand 和 year 属性的获取方法可以直接用 brand() 和 year() 调用, chain = true 使得 setter 方法可以链式调用,如 brand("Toyota").year(2022) 。2. @ExtensionMethod扩展方法- 功能描述:允许向现有类型添加新方法,能解决在使用某些API时功能不够丰富的问题,扩展已有类的功能,使得在代码中可以像调用原生方法一样调用扩展后的方法,增强了代码的灵活性和复用性。


举个栗子:

import lombok.experimental.ExtensionMethod;
import java.util.ArrayList;
import java.util.List;

class ListExtension {
??? public static int sum(List list) {
??????? return list.stream().mapToInt(Integer::intValue).sum();
??? }
}

@ExtensionMethod(ListExtension.class)
public class Main {
??? public static void main(String[] args) {
??????? List numbers = new ArrayList<>();
??????? numbers.add(1);
??????? numbers.add(2);
??????? numbers.add(3);
??????? int result = numbers.sum();? // 调用扩展方法
??????? System.out.println(result);
??? }
}

这里定义了 ListExtension 类,其中有个 sum 方法用于计算 List 中元素的总和。通过 @ExtensionMethod 注解将这个类的方法扩展到 List 类型上,之后在 Main 类中就能直接对 List 对象调用 sum 方法了。3. @FieldDefaults访问修饰符- 功能描述:用于设置类中字段的默认访问修饰符、是否为 final 等属性,以此统一控制类内所有字段的相关特性,让代码风格更加规整,便于阅读和维护,减少代码中对字段修饰符逐个设置的重复性工作。

举个栗子:

import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldDefaults.AccessLevel;

@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
class MyClass {
??? int myField;
??? String anotherField;
}


在 MyClass 中,使用 @FieldDefaults 注解将所有字段的默认访问级别设为 PRIVATE 且都标记为 final ,无需为每个字段单独添加 private 和 final 修饰符了。4.@OnMethod、

@OnConstructor、

@OnParam增加逻辑- 功能描述:这几个注解可在方法、构造函数、参数层面添加额外的逻辑,实现更细粒度的控制和扩展。比如使用 @OnMethod 可以在方法执行的前后添加一些自定义逻辑,像记录日志、进行参数验证等;

@OnConstructor 能在构造函数调用前后做类似操作;

@OnParam 可针对方法参数进行特定处理。


举个栗子:

import lombok.experimental.OnMethod;
import java.util.concurrent.TimeUnit;

class MethodLogger {
??? @OnMethod(
??????????? before = "System.out.println(\"方法执行前: \" + java.util.Arrays.toString($args))",
??????????? after = "System.out.println(\"方法执行后\")"
??? )
??? public static void doSomething(int num) {
??????? try {
??????????? TimeUnit.SECONDS.sleep(1);
??????? } catch (InterruptedException e) {
??????????? e.printStackTrace();
??????? }
??? }
}

public class Main {
??? public static void main(String[] args) {
??????? MethodLogger.doSomething(5);
??? }
}

在上述代码中, @OnMethod 注解为 doSomething 方法添加了前置和后置逻辑,在方法执行前会打印传入的参数信息,执行后会输出相应提示,方便进行调试或记录相关信息。


5. @UtilityClass工具类- 功能描述:用于标识一个类为工具类,它会自动生成私有构造函数,防止类被实例化,同时将类中的所有静态方法和字段暴露出来,方便使用,遵循了工具类的设计规范,让代码结构更清晰,调用更方便。



举个栗子:

import lombok.experimental.UtilityClass;

@UtilityClass
public class StringUtils {
??? public static boolean isEmpty(String str) {
??????? return str == null || str.isEmpty();
??? }
}

在这个示例中, StringUtils 类被标记为 @UtilityClass ,成为了一个工具类,不能被实例化,且其内部的 isEmpty 方法可直接通过类名调用,如 StringUtils.isEmpty("") 。6. @Helper辅助方法- 功能描述:可用于生成辅助方法,把一些通用的、与业务逻辑关联不大但又经常用到的代码提取出来,形成辅助方法,提高代码的可读性和可维护性,使主业务逻辑代码更清晰简洁。


举个栗子:

import lombok.experimental.Helper;

class MathHelpers {
??? @Helper
??? public static int max(int num1, int num2) {
??????? return Math.max(num1, num2);
??? }
}

public class Main {
??? public static void main(String[] args) {
??????? int result = MathHelpers.max(5, 3);
??????? System.out.println(result);
??? }
}

这里 MathHelpers 类中的 max 方法通过 @Helper 注解成为辅助方法,方便在其他地方调用,将简单的求最大值逻辑封装起来,使调用处代码更清晰。7. @FieldNameConstants常量- 功能描述:可为类中的字段生成对应的字符串常量,避免在代码中使用硬编码的字符串字面量来表示字段名,提高代码的可维护性和可读性,尤其在涉及到反射、序列化等场景下更有优势,方便根据常量来获取或操作对应字段。


举个栗子:

import lombok.experimental.FieldNameConstants;

@FieldNameConstants
class Person {
??? private String name;
??? private int age;
}

public class Main {
??? public static void main(String[] args) {
??????? System.out.println(Person.NAME);
??? }
}

在 Person 类上使用 @FieldNameConstants 注解后,

会为 name 字段生成 NAME 字符串常量,可直接在代码中使用,便于后续的相关操作。8. @SuperBuilder继承构造器- 功能描述:用于生成具有父类和子类构造器的构造器模式,简化了在继承层次结构中复杂对象的创建过程,子类可以继承父类的构造器结构并方便地设置父类的字段,让对象的创建代码更清晰、易读且易于维护。


举个栗子:

import lombok.experimental.SuperBuilder;

class Animal {
??? private String name;
??? public Animal(String name) {
??????? this.name = name;
??? }
}

@SuperBuilder
class Dog extends Animal {
??? private String breed;
??? public Dog(String name, String breed) {
??????? super(name);
??????? this.breed = breed;
??? }
}

public class Main {
??? public static void main(String[] args) {
??????? Dog dog = Dog.builder()
????????????? .name("旺财")
????????????? .breed("中华田园犬")
????????????? .build();
??????? System.out.println(dog);
??? }
}

在上述代码中, Dog 类继承自 Animal 类,使用 @SuperBuilder 后,能通过构建器方便地设置父类( Animal 类中的 name 属性)以及自身( Dog 类的 breed 属性)的属性值来创建对象。9. @Tolerate保留方法- 功能描述:可让Lombok忽略现有的方法或构造函数,避免与Lombok生成的代码产生冲突,适用于需要保留自定义方法或构造函数的场景,保证了在使用Lombok自动生成代码的同时,原有手动编写的特定方法或构造函数能正常使用。


举个栗子:

import lombok.Data;
import lombok.experimental.Tolerate;

@Data
class CustomClass {
??? private String customField;

??? @Tolerate
??? public CustomClass() {
??????? // 自定义无参构造函数
??? }
}


在 CustomClass 中,使用 @Tolerate 注解标注了自定义的无参构造函数,这样即便类使用了 @Data 注解(会自动生成构造函数等代码),这个自定义的无参构造函数也能保留并正常使用。10. @Jacksonized配合Jackson库

- 功能描述:使Lombok生成的类更易于与Jackson库进行序列化和反序列化,自动配置Jackson的一些注解和设置,减少了手动为类添加Jackson相关注解(如 @JsonProperty 等)的工作量,简化了配置过程,方便对象在JSON格式与Java对象之间的转换。


举个栗子:

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.experimental.Jacksonized;

@Jacksonized
@Data
class User {
??? private String username;
??? private int age;
}

public class Main {
??? public static void main(String[] args) throws Exception {
??????? User user = new User();
??????? user.setUsername("小明");
??????? user.setAge(20);

??????? ObjectMapper objectMapper = new ObjectMapper();
??????? String json = objectMapper.writeValueAsString(user);
??????? System.out.println(json);

??????? User deserializedUser = objectMapper.readValue(json, User.class);
??????? System.out.println(deserializedUser);
??? }
}


在这个示例中, User 类使用了 @Jacksonized 注解,配合 @Data 注解,在进行JSON序列化和反序列化时更加方便,无需额外为属性添加很多Jackson相关的注解就能顺利实现转换操作。11. @StandardException异常类- 功能描述:用于创建标准的异常类,遵循一定的规范和约定,使异常处理更加统一和规范,在整个项目中保持异常类的一致性,便于理解、捕获和处理异常情况,提升代码的可读性和可维护性。


举个栗子:

import lombok.experimental.StandardException;

@StandardException
public class BusinessException extends RuntimeException {
}

public class Main {
??? public static void main(String[] args) {
??????? try {
??????????? throw new BusinessException();
??????? } catch (BusinessException e) {
??????????? e.printStackTrace();
??????? }
??? }
}


这里通过 @StandardException 注解创建了 BusinessException 异常类,它继承自 RuntimeException ,遵循了一定的标准规范,在项目中使用时能让异常处理更规范有序。


12. @var变量类型推断- 功能:这是一种类型推断的实验性功能。它可以根据变量的初始化表达式自动推断变量的类型,类似于JavaScript中的 var 关键字。不过,这种方式可能会使代码的可读性在某些复杂场景下降低,因为从变量声明上不容易直接看出类型。


13. @val局部变量类型推断- 功能: @val 是一个局部变量类型推断的实验性注解。它与 @var 类似,但更侧重于不可变( final )局部变量的类型推断。它的目的是减少在局部变量声明时的类型冗长表述,特别是对于一些复杂的泛型类型等情况。


举个栗子:

import lombok.experimental.val;
import java.util.ArrayList;
import java.util.List;
public class Main {
?? public static void main(String[] args) {
????? @val List stringList = new ArrayList<>();
????? // 后续使用stringList进行操作
?? }
}

- 注意事项:在实际使用中,这种注解因为是实验性的,可能在代码检查工具或者不同编译器环境下会有不兼容的情况出现,并且在代码维护和理解上,对于不熟悉该注解的开发者可能会造成困惑。

14. @FieldDefaults字段默认信息- 功能:这个注解用于设置类中字段的默认访问修饰符、是否为 final 等属性。它可以统一控制类中所有字段的某些属性,使得代码风格更加规整。



举个栗子:

import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldDefaults.AccessLevel;
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
class MyClass {
?? int myField;
}

- 在实验性功能中的特点:虽然这个注解提供了便利的字段属性设置方式,但作为实验性功能,它可能在和其他Lombok注解或者Java语言特性(如继承、接口实现等场景)的交互中出现一些预料之外的情况,需要谨慎使用并进行充分测试。


需要注意的是,由于这些都是实验性功能,在不同版本的Lombok以及不同开发环境下,可能存在兼容性问题或者功能表现的差异,使用时要谨慎并做好相应测试。


能不使用建议不要使用,容易引起各种问题。



4.使用Lombok的经验和技巧



1. 合理选择注解- 根据实际需求选择合适的Lombok注解。如果只是需要简单的获取和设置属性值,使用 @Getter 和 @Setter 即可。


如果需要一个包含所有属性的构造函数,使用 @AllArgsConstructor ;若只需无参构造函数,就用 @NoArgsConstructor 。

- 对于数据传输对象(DTO)或实体类, @Data 注解很方便,它能自动生成常用方法,但要注意它生成的 equals() 和 hashCode() 方法在某些复杂场景(如继承关系)下可能不符合预期,需要谨慎使用或手动调整。2. 与IDE配合使用- 确保在IDE中安装并正确配置Lombok插件,这样可以更好地利用代码自动补全和导航功能。例如,在IntelliJ IDEA中,安装插件后,能够像识别普通方法一样识别Lombok生成的方法,便于开发过程中的调用和查看。- 熟悉IDE中Lombok相关的设置。有些IDE可以设置Lombok的处理级别,比如在代码检查和提示中如何对待Lombok生成的方法等。3. 考虑团队协作- 在团队开发中,确保所有成员都了解Lombok的使用方式和原理。因为Lombok自动生成的代码在代码审查时可能会被忽略,如果团队成员对其不熟悉,可能会对代码的理解产生偏差。- 可以在团队的代码规范文档中,加入Lombok的使用规范,例如哪些类适合用哪种注解,如何处理Lombok可能带来的潜在问题等。4. 结合构建工具- 在Maven或Gradle构建项目时,注意Lombok依赖的版本管理。及时更新Lombok版本,以获取新的功能和修复可能的漏洞,但也要注意新版本可能带来的兼容性问题。- 对于多模块项目,确保Lombok依赖在各个模块中的配置正确,尤其是在模块之间传递使用了Lombok注解的类时,要保证编译和运行环境的一致性。5. 测试和调试- 由于Lombok是在编译阶段自动生成代码,在调试时可能会遇到一些困惑。如果发现代码运行时行为不符合预期,需要考虑是否是Lombok生成的方法导致的。可以通过查看编译后的字节码或者反编译后的代码来确认。- 在编写单元测试时,同样要注意测试Lombok生成的方法。例如,测试 @Data 注解生成的 equals() 和 hashCode() 方法是否符合实际需求,或者测试 @Builder 模式构建的对象是否正确初始化。


5.可能问题及解决方法


1. IDE兼容问题

- 问题描述:如果没有安装Lombok插件,IDE可能无法识别Lombok注解,导致代码出现错误提示,如找不到自动生成的方法(像getter、setter等)。

- 解决方法:

- 对于IntelliJ IDEA,在插件市场搜索“Lombok”并安装,安装完成后重启IDE,让其能够正确识别Lombok注解并提供代码补全、编译检查等功能。

- Eclipse也有对应的Lombok插件,可通过Eclipse Marketplace安装,安装后重启Eclipse即可。

2. 编译问题

- 问题描述:在使用Maven或Gradle构建项目时,如果没有正确配置Lombok依赖,会导致编译失败。例如,Maven没有添加 lombok 依赖或者Gradle没有正确配置 annotationProcessor 路径。

- 解决方法:

- Maven项目:在 pom.xml 文件中添加正确的Lombok依赖。确保依赖的范围( scope )设置正确,一般是 provided ,这意味着Lombok在编译时需要,但在运行时由JDK提供支持。

xml

org.projectlombok

lombok

1.18.28

provided

- Gradle项目:在 build.gradle 文件中添加以下配置,确保Lombok作为编译时的依赖并且配置了注解处理器路径。

groovy

compileOnly 'org.projectlombok:lombok:1.18.28'

annotationProcessor 'org.projectlombok:lombok:1.18.28'

- 同时,检查JDK版本是否兼容,Lombok通常支持较新版本的JDK,如JDK 8及以上。

3. 继承和接口实现问题

- 问题描述:在继承或实现接口场景下,Lombok生成的方法可能不符合预期。

例如, @Data 注解生成的 equals() 和 hashCode() 方法可能没有考虑继承层次结构中父类的属性。


- 解决方法:

- 如果需要考虑父类属性,手动重写 equals() 和 hashCode() 方法,并且在方法中加入父类属性的比较逻辑。或者使用 @EqualsAndHashCode(callSuper = true) 注解,这样在生成方法时会考虑父类的属性。


- 在接口实现方面,如果接口定义了一些访问方法,而Lombok生成的方法签名和接口要求不完全一致(如访问级别等),可以通过手动调整方法签名或者修改Lombok注解的参数来匹配接口要求。

4. 循环依赖问题

- 问题描述:当两个类通过Lombok注解相互引用时,可能会产生循环依赖。例如, A 类中有一个 B 类型的属性, B 类中又有一个 A 类型的属性,并且都使用了Lombok生成的方法。


- 解决方法:

- 重新设计类结构,避免循环依赖。如果无法避免,可以考虑使用接口或者抽象类来打破循环。

- 手动实现部分方法,避免完全依赖Lombok自动生成的方法,在实现过程中谨慎处理循环引用的部分。


6.总结

以上就是本期lombok的内容,总之,她有优势和劣势,看您能否很好驾驭她。



程序员鼓励师来哦(??????)

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表