Java中lombok的使用详解

Java中lombok的使用详解


在开发过程中,有一些代码总是要重复编写,比如 getter / setter、构造器方法、toString方法等等,很浪费时间,为了节约时间使用 lombok 插件来减少相同代码的编写,使用注解来实现,本文将解释一下 lombok 中的常用注解的一些技巧。

lombok的安装

  1. 首先在 IDEA 中安装 lombok 插件,一般情况下该插件已经和 IDE 绑定安装了。
  2. 添加 maven 依赖
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>

完成上述两个步骤就可以在代码中使用 lombok 了。

lombok的使用

@Data

在类上注解,提供该类所有属性的 getter/setter 方法,还提供了 equals、canEqual、hashCode、toString 方法。

使用 @Data 注解如下:

@Data
public class Person {
    private String name;
    private int age;
}

经过编译代码如下:

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public void setAge(final int age) {
        this.age = age;
    }

    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Person)) {
            return false;
        } else {
            Person other = (Person)o;
            if (!other.canEqual(this)) {
                return false;
            } else if (this.getAge() != other.getAge()) {
                return false;
            } else {
                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(final Object other) {
        return other instanceof Person;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        result = result * 59 + this.getAge();
        Object $name = this.getName();
        result = result * 59 + ($name == null ? 43 : $name.hashCode());
        return result;
    }

    public String toString() {
        return "Person(name=" + this.getName() + ", age=" + this.getAge() + ")";
    }
}

@Getter、@Setter

在属性上注解:为该属性提供getter方法

public class Person {
    @Getter
    private String name;
    private int age;
}

在类上注解:为该类所有属性提供getter方法

@Getter
public class Person {
    private String name;
    private int age;
}

@Setter注解和@Getter是一个意思,不在重复粘贴代码展示。

@Slf4j

作用在类上,此注解一般在业务层使用,将日志打印出来。

代码如下:(下面代码只是为了举例,业务不是重点)

@Service
@Slf4j
public class TbCustomerServiceImpl extends ServiceImpl<TbCustomerMapper, TbCustomer> implements TbCustomerService {
    
    private StudentService studentService;
    
    public TbCustomerServiceImpl(StudentService studentService) {
        this.studentService = studentService;
    }
    
    @Override
    public List<TbCustomer> queryAll() {
        List<TbCustomer> list = this.lambdaQuery().list();
        // 花括号为占位符,将list的数据放在其中
        log.debug("查出的数据为 {}", list);
        return list;
    }
}

@AllArgsConstructor

作用在类上,使该类提供一个全参构造方法,此时该类只有全参构造方法,没有默认的无参构造方法

代码如下:

@AllArgsConstructor
public class Person {
    private String name;
    private int age;
}

编译后代码如下:

public class Person {
    private String name;
    private int age;

    public Person(final String name, final int age) {
        this.name = name;
        this.age = age;
    }
}

@NoArgsConstructor

作用在类上,使该类提供一个无参构造方法,一般配合@AllArgsConstructor此注解一起使用,同时提供全参构造方法和无参构造方法。

还有一种我比较喜欢的用法:

@AllArgsConstructor(staticName = "of")
@NoArgsConstructor(staticName = "of")
public class Person {
    private String name;
    private int age;
}

加了staticName这个参数可以更快的生成对象:

public void Test(){
        Person lisi = Person.of("lisi", 2);
        Person of = Person.of();
}

当只有@Data注解时,加了staticConstructor参数如下:

@Data(staticConstructor = "of")
public class Person {
    private String name;
    private int age;
}

则默认使用无参构造创建对象:

public void Test(){
    Person of = Person.of();
}

@EqualsAndHashCode

此注解作用于类上,生成equals、canEqual、hashCode方法。

同时还有一个优点,在重写equals方法时同时重写了HashCode方法,为啥要都重写才行呢,我下面举个例子来说明:

  1. 我们有个只重写equals方法的类,使用set集合来存储一些这个类对象(这些类对象要有重复的)
  2. 当循环打印这个set集合应该把重复的对象去掉,但是并没有

代码如下:

@Test
public void Test(){
    HashSet<Person> set = new HashSet<>();
    set.add(new Person("lisi",22));
    set.add(new Person("lisi",22));
    set.stream().forEach(s -> System.out.println(s));
}

打印的日志如下:

Person(name=lisi, age=22)
Person(name=lisi, age=22)

原因如下:

  1. 这是因为去重时先去比较了hashcode是否相同,因为没有重写hashcode方法所以去执行了object类中的hashcode方法,返回的是不同引用地址的对象所以是false,直接不执行equals方法,所以最后返回的也是false。
  2. 如果重写了hashcode方法,进行比较时对比的是对象所有属性的hashcode值是否相同,返回结果自然是true,在去调用equals方法,发现两个方法确实是相等的,于是返回true,程序才能执行正常。

如果没有听懂建议去搜索对应问题的详细回答,我这里只是进行简述。

@NonNull

作用于属性上,提供关于此参数的非空检查,如果参数为空,则抛出空指针异常。

public class Person {
    @NonNull
    private String name;
    private int age;

}

@RequiredArgsConstructor

该注解作用于类上,所有带有@NonNull注解或者带有final修饰的成员变量作为参数生成构造方法。(构造注入)

代码如下:

@Service
@RequiredArgsConstructor
public class TbCustomerServiceImpl extends ServiceImpl<TbCustomerMapper, TbCustomer> implements TbCustomerService {

    private final StudentService studentService;

    @Override
    public Student selectStudentById() {
        Student student = studentService.selectStudentById(2);
        return student;
    }
}

@ToString

作用在类上,为所有属性提供toString方法,具体代码见上方@Data注解。

@SneakyThrows

作用于方法上,将方法内的代码添加了一个try-catch处理,捕获异常catch中用Lombok.sneakyThrow(e)抛出异常。使用@SneakyThrows(BizException.class)指定抛出具体异常。

代码如下:

@SneakyThrows
public void Test() {
    int num = 0;
    num = 1 / 0;
}

编译后如下:

public void Test() {
    try {
        int num = 0;
        num = 1 / 0;
    } catch (Throwable var3) {
        throw var3;
    }
}

@Builder

作用于类上,实现流式操作,思想为设计模式中的创建者模式。

代码如下:

@Builder
public class Person {
    private String name;
    private int age;
}

如何使用:

public void Test(){
    Person lisi = Person.builder().age(11).name("lisi").build();
}

上述流式操作可以不全传参数,不穿的参数为null。

@Cleanup

作用于变量,保证该变量代表的资源会被自动关闭,默认调用资源的close()方法,如果该资源有其它关闭方法,可使用@Cleanup(“methodName”)来指定。

代码举例如下:

public class FileCopyExample {
    public static void main(String[] args) {
        String sourceFile = "source.txt";
        String targetFile = "target.txt";

        try (
                @Cleanup FileInputStream inputStream = new FileInputStream(sourceFile);
                @Cleanup FileOutputStream outputStream = new FileOutputStream(targetFile);
        ) {
            byte[] buffer = new byte[1024];
            int bytesRead;

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

@Synchronized

作用于类方法或实例方法上,效果与synchronized相同。区别在于锁对象不同,对于类方法和实例方法,synchronized关键字的锁对象分别是类的class对象和this对象,而@Synchronized的锁对象分别是私有静态final对象lock和私有final对象lock。也可以指定锁对象。

代码如下:

public class example{

    private final Object lock = new Object();

    @Synchronized
    public void one(){
        System.out.println("one1");
    }

    @Synchronized("lock")
    public void two(){
        System.out.println("two");
    }
}

编译后如下:

public class example {
    private static final Object $LOCK = new Object[0];
    private final Object lock = new Object();

    example() {
    }

    public static void one() {
        synchronized($LOCK) {
            System.out.println("one1");
        }
    }

    public void two() {
        synchronized(this.lock) {
            System.out.println("two");
        }
    }
}

总结: Lombok可以提高代码的生产力和可读性,但也需要谨慎使用,有时也会无法满足需求也会让不熟悉的开发人员增加挑战等等、特别是在大型团队或有特殊要求的项目中。团队需要权衡Lombok的好处和坏处,并根据项目的具体需求决定是否使用它。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值