为什么有的团队严禁使用Lombok?

一、介绍

Java,作为一款非常热门的编程语言,尽管它有着非常丰富的语言特性,完全面向对象编程,编程高度规范化,但是也有一个最受大家诟病的一个缺点:啰嗦,尤其是当你开发了很多年之后,你会明显的感受到,相比动态语言,java 定义变量之前,要先创建类,然后定义变量类型,每个类要写很多的get/set/toString/hashCode/equals等等方法。

尤其是当一个实体类,高达几十个变量时,写完get、set方法之后,一个实体类的长度快接近一千行。
在这里插入图片描述

为了避免写这些“罗嗦”的方法,很多程序员一直在寻觅着找一个能够使他们摆脱这种重复劳动工作的工具,例如:idea、eclipse 开发工具的快捷生成get、set方法的工具,还有我们今天要谈论的这个Lombok工具。

二、Lombok

Lombok 是一款非常流行的代码简洁工具,利用它的注解特性,直接就可以帮我们省去高大几百行的get、set方法,操作非常方便。

如果是idea开发工具,可以直接在preferences -> plugins里面搜索lombok,然后点击安装即可!

在这里插入图片描述

接着,在项目工程中导入lombok依赖包!

<dependency> 
    <groupId>org.projectlombok</groupId> 
    <artifactId>lombok</artifactId> 
    <version>1.18.12</version> 
    <scope>provided</scope> 
</dependency> 

最后,只需要在对应的实体类上加上@Data注解,即可完成类属性get/set的注入。

import lombok.Data;

@Data 
public class User {
    
     
    private String id; 
    private String age; 
    private String name; 
  
 //可以不用显式写get、set方法 
} 

使用@Data注解在类上,这个实体类中的属性就不需要显式写get、set方法了。

对这个类进行编译之后,我们打开User.class文件,看看编译后的文件内容长啥样?

public class User {
    
     
    private String id; 
    private String age; 
    private String name; 
 
    public User() {
    
     
    } 
 
    public String getId() {
    
     
        return this.id; 
    } 
 
    public String getAge() {
    
     
        return this.age; 
    } 
 
    public String getName() {
    
     
        return this.name; 
    } 
 
    public void setId(String id) {
    
     
        this.id = id; 
    } 
 
    public void setAge(String age) {
    
     
        this.age = age; 
    } 
 
    public void setName(String name) {
    
     
        this.name = name; 
    } 
 
    public boolean equals(Object o) {
    
     
        if (o == this) {
    
     
            return true; 
        } else if (!(o instanceof User)) {
    
     
            return false; 
        } else {
    
     
            User other = (User)o; 
            if (!other.canEqual(this)) {
    
     
                return false; 
            } else {
    
     
                label47: {
    
     
                    Object this$id = this.getId(); 
                    Object other$id = other.getId(); 
                    if (this$id == null) {
    
     
                        if (other$id == null) {
    
     
                            break label47; 
                        } 
                    } else if (this$id.equals(other$id)) {
    
     
                        break label47; 
                    } 
 
                    return false; 
                } 
 
                Object this$age = this.getAge(); 
                Object other$age = other.getAge(); 
                if (this$age == null) {
    
     
                    if (other$age != null) {
    
     
                        return false; 
                    } 
                } else if (!this$age.equals(other$age)) {
    
     
                    return false; 
                } 
 
                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(Object other) {
    
     
        return other instanceof User; 
    } 
 
    public int hashCode() {
    
     
        int PRIME = true; 
        int result = 1; 
        Object $id = this.getId(); 
        int result = result * 59 + ($id == null ? 43 : $id.hashCode()); 
        Object $age = this.getAge(); 
        result = result * 59 + ($age == null ? 43 : $age.hashCode()); 
        Object $name = this.getName(); 
        result = result * 59 + ($name == null ? 43 : $name.hashCode()); 
        return result; 
    } 
 
    public String toString() {
    
     
        return "User(id=" + this.getId() + ", age=" + this.getAge() + ", name=" + this.getName() + ")"; 
    } 
} 

很清晰的看到,使用@Data注解之后,User类新增了get、set、hashCode、equals和toString方法。

通过上面的例子,大家可以发现,使用@Data注解可以大大减少了代码量,使代码非常简洁,这也是很多开发者热衷于使用Lombok的主要原因。

Lombok的工作原理是怎么实现的呢?

由于Java的官方版本没有提供这种快速生成方法的注解工具,类似Lombok这样的工具,其实都是使用了从Java 6和JSR 269的Annotation Processing技术中实现方法的注入。

简单的说,就是使用了 Java 非公开的 API,在 javac 编译代码时,通过强类型转换获取JavacAnnotationProcessor对象,再从JavacAnnotationProcessor的方法里面拿到抽象语法树(AST)做强制修改,注入get、set等方法。

使用Lombok这种方案,有个最大的好处,就是可以节省大量的重复代码,让代码更佳简洁!但是也有很多弊端!

三、有哪些坏处呢?

3.1、强迫队友也安装 Lombok

当你在使用Lombok工具插件来快速开发项目的时候,如果别的同事也要和你一起协作开发项目,那么他不得不也要安装Lombok插件,不然项目编译会报错。

3.2、代码可调试性降低

代码可调试性会降低,为什么会这么说呢?

Lombok虽然给我们节省了get和set方法的编程,但是如果我想知道类的某个属性被哪些方法操作给set了,如果用原生的方法,可以很好的知道调用方。但是如果使用Lombok插件来生成,这个时候你根本无从得知。甚至没办法调试!

3.3、不懂 Lombok 注解,会踩坑

我们知道,使用@Data会重写hashCode()和equals()方法,如果是单个实体类,没有继承的话,你使用@Data不会产生问题。

但是如果这个实体类又继承了父类,@Data只会重写子类的hashCode()和equals()方法,不会把父类的属性加进去,这样就会导致,例如当你在使用HashMap的时候,用当前这个实体类作为key,可能会得到意想不到的结果。

遇到这种情况,你可以在类上加上这个注解@EqualsAndHashCode(callSuper=true),子类的hashCode()和equals()方法会加入父类的属性。

3.4、破坏封装性

封装是 java 面向对象编程中非常重要的一个特性。

例如,针对User实体类,我新加一个tag属性,我只想暴露它的get方法,不想暴露set方法给外部,没有用@Data注解的时候,我可以很灵活的进行编程,但是使用@Data注解之后,属性tag被完全暴露在外界了。

public class User {
    
     
 
    private String id; 
 
    private String age; 
 
    private String name; 
 
    private String tag = "学生"; 
 
    public String getTag() {
    
     
        return tag; 
    } 
     
} 

3.5、影响 jdk 升级

其实以上的坑点,都不算什么很大的坑点,在我看来,最大的坑点其实就是Lombok的工作原理,使用了非官方支持的 API 接口,通过程序强制植入方式来修改类,实现get、set等方法的注入。

按照如今 JDK 的升级频率,每半年都会推出一个新的版本,但是Lombok作为一个第三方工具,并且是由开源团队维护的,那么他的迭代速度是无法保证的。

假如某天JDK把这种后门堵住了,那Lombok基本上就不能用了,到时候又是个麻烦事情。

四、总结

Lombok 作为一款非常流行的工具插件,肯定有它自身的优势所在,到底建不建议在日常开发中使用,我个人其实是一个中立的态度,如果你们团队的人都喜欢它,那推荐你使用,在使用之前,最好培训一下,有哪些坑点,避免踩坑。

如果多数人不太喜欢用它,那就不推荐你使用,很多公司禁止你使用它的原因,其实这种插件有点类似那种流氓插件,工作原理不是官方所认可的方式来实现,假如某天新版本的 jdk 突然把这个漏洞给堵住了,那么项目想要升级 jdk,就比较困难。

因此大家在评估要不要在代码中引入Lombok的时候,在想它的优点同时,能够考虑到它会带来的哪些问题,以便更好的做决定!

猜你喜欢

转载自blog.csdn.net/Monsterof/article/details/120840897