精华内容
下载资源
问答
  • 不得承认,Lombok 是一个很不错的 Java 库,它可以你在少写代码的同时耍耍酷,简单的几个注解,就可以干掉一大片模板代码。但是,所有的源代码很多时候是用来阅读的,只有很少的时间是用来执行的 (你可以细品这...

    不得不承认,Lombok 是一个很不错的 Java 库,它可以让你在少写代码的同时耍耍酷,简单的几个注解,就可以干掉一大片模板代码。但是,所有的源代码很多时候是用来阅读的,只有很少的时间是用来执行的 (你可以细品这句话)。

     

    接下来,我将用几个大家耳熟能详的场景,重演我们是如何掉入 Lombok 的戏法陷阱。

     

    # 爱的开始,恨的起源

     

    面对 Lombok 提供的诸多 “神走位”,你并不会介意在 IDE 上新增一个插件。对于 IntelliJ IDEA 玩家而言,只需搜索 “Lombok Plugin” 便可找到这款神器并安装上它。爱上 Lombok 从安装 Lombok 插件开始,恨也从此萌芽。

     

    没使用 Lombok 之前,我们的源代码看起来是这一的:

    public class MyObject{    private Long id;    private String name;    private int age;    private int gender;
        public Long getId(){        return id;    }    public void setId(Long id){        this.id = id;    }    public String getName(){        return name;    }    public void setName(String name){        this.name = name;    }    public int getAge(){        return age;    }    public void setAge(int age){        this.age = age;    }    public int getGender(){        return gender;    }    public void setGender(int gender){        this.gender = gender;    }
        @Override    public boolean equals(Object o){        if(this == o){            return true;        }        if(o == null || getClass() != o.getClass()){            return false;        }        MyObject obj = (MyObject) o;        return age = obj.age &&            gender = obj.gender &&            Objects.equals(id,obj.id) &&            Objects.queals(name,obj.name);    }
        @Override    public int hashCode(){        return Objects.hash(id,name,age,gender);    }
        @Override    public String toString(){        return "MyObject{"+            "id="+id+            "name="+name+            "age="+age+            "gender="+gander+            "}";    }}

     

    每个 JavaBean 都会充斥着如上述 getter,setter,equals,hashCode 和 toString 的模板代码,这看起来像一个偏胖的人(不得不承认 Java 是一个有缺陷的编程语言)。

     

    当我们安装好 Lombok 插件后,IDE 便可以识别其酷炫的注解,使用 Lombok 的 @Getter 和 @Setter 注解后,代码会像下面这样看起来很苗条:

    @Getter@Setterpublic class MyObject{    private Long id;    private String name;    private int age;    private int gender;
        @Override    public boolean equals(Object o){        if(this == o){            return true;        }        if(o == null || getClass() != o.getClass()){            return false;        }        MyObject obj = (MyObject) o;        return age = obj.age &&            gender = obj.gender &&            Objects.equals(id,obj.id) &&            Objects.queals(name,obj.name);    }
        @Override    public int hashCode(){        return Objects.hash(id,name,age,gender);    }
        @Override    public String toString(){        return "MyObject{"+            "id="+id+            "name="+name+            "age="+age+            "gender="+gander+            "}";    }}

     

    现在的代码是否看起来爽多了?但这还不是最爽的时候。

     

    既然其他方法都替换掉了,那把 toString 方法也一起拿掉吧。如你所愿,可以使用 @ToString 注解去掉对于的方法:

    @Getter@Setter@EqualsAndHashCodepublic class MyObject{    private Long id;    private String name;    private int age;    private int gender;
        @Override    public String toString(){        return "MyObject{"+            "id="+id+            "name="+name+            "age="+age+            "gender="+gander+            "}";    }}

     

    经过 Lombok 的戏法之后,相比一开始的代码,看起来是不是很酷炫,很苗条,很性感?你以为到此为止了?

     

    远不止于此。你会发现类名上一大坨注解看起来好别扭,Lombok 提供了一个组合注解 @Data,可以替换掉类名头上那坨像翔一样的东西:

    @Datapublic class MyObject{    private Long id;    private String name;    private int age;    private int gender;}

     

    现在,Lombok 是否让你的对象成为了你心目中完美的样子?魔鬼的 “身材”,酷炫精炼。Lombok 还有其他一些注解,如 @Slf4j,@NoArgsConstructor,@AllArgsConstructor 等等,介绍 Lombok 用法不是本文重点。

     

    以上代码行数的变化过程,也许是无数程序员爱上 Lombok 的主要原因吧,这就像一个肥胖的人逐渐变成一个身材苗条的人。

     

    同时也让你看到了一个现象:你以为程序员很懒吗?其他有些时候他们比你想象中的还要懒。在爽的同时,也为代码种下了祸根。

     

    # 扭曲的审美,爱的隐患

     

    扭曲的审美,导致了被审视的对象处于亚健康状态。使用 Lombok 插件之后,我们的代码也处于 “亚健康” 状态。还是回归一开始的那句话:所有的源代码很多时候是用来阅读的,只有很少的时间是用来执行的。

     

    本质上讲,我们都追求减少程序中的样板代码以使其代码更精炼简洁,从而提高代码的可读性和可维护性。

     

    但 Lombok 并没有达到我们所追求的这一愿景,它仅仅是利用 Java 语言在编译时的空档期,使用一种很取巧的方式,将我们所需要的方法注入(写入)到当前的类中,这种过程很像在 hack 我们的代码,只是一种看起来酷炫的把戏。

     

    这种把戏并不智能和安全,反而会破坏 Java 代码现有的特性以及代码的可读性。

     

    下面,结合我自己使用 Lombok 之后的感受,谈谈 Lombok 带来的几大痛点。

     

    1. JDK 版本问题

     

    当我想要将现有项目的 JDK 从 Java 8 升级到 Java 11 时,我发现 Lombok 不能正常工作了。

     

    于是我不得不将所有的 Lombok 注解从项目源代码中清除,并使用 IDE 自带的功能生成 getter/setter,equals,hashCode,toString 以及构造器等方法,你也可以使用 Delombok 工具完成这一过程。但这终究会消耗你很多的时间。

     

    2. 胁迫使用

     

    当你的源代码中使用了 Lombok,恰好你的代码又被其他的人所使用,那么依赖你代码的人,也必须安装 Lombok 插件 (不管他们喜不喜欢),同时还要花费时间去了解 Lombok 注解的使用情况,如果不那么做,代码将无法正常运行。使用过 Lombok 之后,我发现这是一种很流氓的行为。

     

    3. 可读性差

     

    Lombok 隐藏了 JavaBean 封装的细节,如果你使用 @AllArgsConstructor 注解,它将提供一个巨型构造器,让外界有机会在初始化对象时修改类中所有的属性。

     

    首先,这是极其不安全的,因为类中某系属性我们是不希望被修改的;另外,如果某个类中有几十个属性存在,就会有一个包含几十个参数的构造器被 Lombok 注入到类中,这是不理智的行为;

     

    其次,构造器参数的顺序完全由 Lombok 所控制,我们并不能操控,只有当你需要调试时才发现有一个奇怪的 “小强” 在等着你;

     

    最后,在运行代码之前,所有 JavaBean 中的方法你只能想象他们长什么样子,你并不能看见。

     

    4. 代码耦合度增加

     

    当你使用 Lombok 来编写某一个模块的代码后,其余依赖此模块的其他代码都需要引入 Lombok 依赖,同时还需要在 IDE 中安装 Lombok 的插件。

     

    虽然 Lombok 的依赖包并不大,但就因为其中一个地方使用了 Lombok,其余所有的依赖方都要强制加入 Lombok 的 Jar 包,这是一种入侵式的耦合,如果再遇上 JDK 版本问题,这将是一场灾难。

     

    5. 得不偿失

     

    使用 Lombok,一时觉得很爽,但它却污染了你的代码,破坏了 Java 代码的完整性,可读性和安全性,同时还增加的团队的技术债务,这是一种弊大于利,得不偿失的操作。如果你确实想让自己的代码更加精炼,同时又兼顾可读性和编码效率,不妨使用主流的 Scala 或 Kotlin 这一基于 JVM 的语言。

     

    # 总 结

     

    Lombok 本身是一个优秀的 Java 代码库,它采用了一种取巧的语法糖,简化了 Java 的编码,为 Java 代码的精简提供了一种方式,但在使用此代码库时,需要了解到 Lombok 并非一个标准的 Java 库。

     

    使用 Lombok,会增加团队的技术债务,降低代码的可读性,增大代码的耦合度和调式难度。

     

    虽然在一定程度上 Lombok 减少了样板代码的书写,但也带来了一些未知的风险。

     

    如果你正在参与一个团队项目(或大型项目), 考虑到后续的升级与扩展,是否使用 Lombok,请与你的团队多沟通和三思

    展开全文
  • 前言如果您正在阅读此文,...我承认,Lombok是一个很不错的Java库,它可以你在少写代码的同时耍耍酷,简单的几个注解,就可以干掉一大片模板代码。但是,所有的源代码很多时候是用来阅读的,只有很少的时间是...

    3de840d42eaa29fdca72b3e4d177bcf9.png

    前言

    如果您正在阅读此文,想必您对Project Lombok已经有了一段时间的了解。您是否正准备拥抱Lombok?还是正准备将如此酷炫的项目推荐给你的团队?如果您准备那么做,不妨听听我在使用Lombok一年后的一些感受。

    我承认,Lombok是一个很不错的Java库,它可以让你在少写代码的同时耍耍酷,简单的几个注解,就可以干掉一大片模板代码。但是,所有的源代码很多时候是用来阅读的,只有很少的时间是用来执行的(你可以细品这句话)。

    a18b364abd3e84e5d59b484dfbea6a8f.png

    一年以前,我和大多数人都认为Lombok的出现会让Java的编码体验会更好,并极力的在我的团队中推荐使用Lombok。一年以后,我开始对此产生顾虑,尤其是在我准备为开源的博客系统Una-Boot升级Java版本时,我才意识到Lombok自己掉入了一个戏法陷阱。在我进一步分析其源代码并理解相关注解的工作原理后,发现我并不需要使用一个非标准的第三方库将Java转换为一个精巧而酷炫的语言。引入Lombok让我的项目一时爽,但一时爽的代价是随着项目推进,技术债务开始累积。

    接下来,我将用几个大家耳熟能详的场景,重演自己是如何掉入Lombok的戏法陷阱。

    爱的开始,恨的起源

    2c3e69e6cac2851200c5f58b39749691.png

    面对Lombok提供的诸多“神走位”,你并不会介意在IDE上新增一个插件。对于IntelliJ IDEA玩家而言,只需搜索“Lombok Plugin”便可找到这款神器并安装上它。爱上Lombok从安装Lombok插件开始,恨也从此萌芽。

    没使用Lombok之前,我们的源代码看起来是这一的:

    public class MyObject{
        private Long id;
        private String name;
        private int age;
        private int gender;
    
        public Long getId(){
            return id;
        }
        public void setId(Long id){
            this.id = id;
        }
        public String getName(){
            return name;
        }
        public void setName(String name){
            this.name = name;
        }
        public int getAge(){
            return age;
        }
        public void setAge(int age){
            this.age = age;
        }
        public int getGender(){
            return gender;
        }
        public void setGender(int gender){
            this.gender = gender;
        }
    
        @Override
        public boolean equals(Object o){
            if(this == o){
                return true;
            }
            if(o == null || getClass() != o.getClass()){
                return false;
            }
            MyObject obj =  (MyObject) o;
            return age = obj.age &&
                gender = obj.gender &&
                Objects.equals(id,obj.id) && 
                Objects.queals(name,obj.name);
        }
    
        @Override
        public int hashCode(){
            return Objects.hash(id,name,age,gender);
        }
    
        @Override
        public String toString(){
            return "MyObject{"+
                "id="+id+
                "name="+name+
                "age="+age+
                "gender="+gander+
                "}";
        }
    }

    f15f6a2891a1c331a6f9216b3596d02f.png

    每个JavaBean都会充斥着如上述getter,setter,equals,hashCode和toString的模板代码,这看起来像一个偏胖的人(不得不承认Java是一个有缺陷的编程语言)。当我们安装好Lombok插件后,IDE便可以识别其酷炫的注解,使用Lombok的@Getter和@Setter注解后,代码会像下面这样看起来很苗条:

    @Getter
    @Setter
    public class MyObject{
        private Long id;
        private String name;
        private int age;
        private int gender;
    
        @Override
        public boolean equals(Object o){
            if(this == o){
                return true;
            }
            if(o == null || getClass() != o.getClass()){
                return false;
            }
            MyObject obj =  (MyObject) o;
            return age = obj.age &&
                gender = obj.gender &&
                Objects.equals(id,obj.id) && 
                Objects.queals(name,obj.name);
        }
    
        @Override
        public int hashCode(){
            return Objects.hash(id,name,age,gender);
        }
    
        @Override
        public String toString(){
            return "MyObject{"+
                "id="+id+
                "name="+name+
                "age="+age+
                "gender="+gander+
                "}";
        }
    }

    你以为Lombok就这点能耐?它还能让你代码的“身材”更苗条,更魔鬼。上面的代码仍然还有改进的空间,我们可以用@EqualsAndHashCode注解替换到equals和hashCode方法:

    @Getter
    @Setter
    @EqualsAndHashCode
    public class MyObject{
        private Long id;
        private String name;
        private int age;
        private int gender;
    
        @Override
        public String toString(){
            return "MyObject{"+
                "id="+id+
                "name="+name+
                "age="+age+
                "gender="+gander+
                "}";
        }
    }

    现在的代码是否看起来爽多了?但这还不是最爽的时候。既然其他方法都替换掉了,那把toString方法也一起拿掉吧.如你所愿,可以使用@ToString注解去掉对于的方法:

    @Getter
    @Setter
    @EqualsAndHashCode
    @ToString
    public class MyObject{
        private Long id;
        private String name;
        private int age;
        private int gender;
    }

    经过Lombok的戏法之后,相比一开始的代码,看起来是不是很酷炫,很苗条,很性感?你以为到此为止了?远不止于此。你会发现类名上一大坨注解看起来好别扭,Lombok提供了一个组合注解@Data,可以替换掉类名头上那坨像翔一样的东西:

    @Data
    public class MyObject{
        private Long id;
        private String name;
        private int age;
        private int gender;
    }

    现在,Lombok是否让你的对象成为了你心目中完美的样子?魔鬼的“身材”,酷炫精炼。Lombok还有其他一些注解,如@Slf4j,@NoArgsConstructor,@AllArgsConstructor等等,介绍Lombok用法不是本文重点。

    c7c013e90e2631fe3b35ce159b467ce8.png

    以上代码行数的变化过程,也许是无数程序员爱上Lombok的主要原因吧,这就像一个肥胖的人逐渐变成一个身材苗条的人。同时也让你看到了一个现象:你以为程序员很懒吗?其他有些时候他们比你想象中的还要懒。在爽的同时,也为代码种下了祸根。

    扭曲的审美,爱的隐患

    扭曲的审美,导致了被审视的对象处于亚健康状态。使用Lombok插件之后,我们的代码也处于“亚健康”状态。还是回归一开始的那句话:所有的源代码很多时候是用来阅读的,只有很少的时间是用来执行的。

    5be8f2d6ffb223a639c6a85d0a0eccd3.png

    本质上讲,我们都追求减少程序中的样板代码以使其代码更精炼简洁,从而提高代码的可读性和可维护性。但Lombok并没有达到我们所追求的这一愿景,它仅仅是利用Java语言在编译时的空档期,使用一种很取巧的方式,将我们所需要的方法注入(写入)到当前的类中,这种过程很像在hack我们的代码,只是一种看起来酷炫的把戏。这种把戏并不智能和安全,反而会破坏Java代码现有的特性以及代码的可读性。下面,结合我自己使用Lombok之后的感受,谈谈Lombok带来的几大痛点。

    1. JDK版本问题

    当我想要将现有项目的JDK从Java 8升级到Java 11时,我发现Lombok不能正常工作了。于是我不得不将所有的Lombok注解从项目源代码中清除,并使用IDE自带的功能生成getter/setter,equals,hashCode,toString以及构造器等方法,你也可以使用Delombok工具完成这一过程。但这终究会消耗你很多的时间。

    2. 胁迫使用

    当你的源代码中使用了Lombok,恰好你的代码又被其他的人所使用,那么依赖你代码的人,也必须安装Lombok插件(不管他们喜不喜欢),同时还要花费时间去了解Lombok注解的使用情况,如果不那么做,代码将无法正常运行。使用过Lombok之后,我发现这是一种很流氓的行为。

    3. 可读性差

    Lombok隐藏了JavaBean封装的细节,如果你使用@AllArgsConstructor注解,它将提供一个巨型构造器,让外界有机会在初始化对象时修改类中所有的属性。首先,这是极其不安全的,因为类中某系属性我们是不希望被修改的;另外,如果某个类中有几十个属性存在,就会有一个包含几十个参数的构造器被Lombok注入到类中,这是不理智的行为;其次,构造器参数的顺序完全由Lombok所控制,我们并不能操控,只有当你需要调试时才发现有一个奇怪的“小强”在等着你;最后,在运行代码之前,所有JavaBean中的方法你只能想象他们长什么样子,你并不能看见。

    4. 代码耦合度增加

    当你使用Lombok来编写某一个模块的代码后,其余依赖此模块的其他代码都需要引入Lombok依赖,同时还需要在IDE中安装Lombok的插件。虽然Lombok的依赖包并不大,但就因为其中一个地方使用了Lombok,其余所有的依赖方都要强制加入Lombok的Jar包,这是一种入侵式的耦合,如果再遇上JDK版本问题,这将是一场灾难。

    5. 得不偿失

    使用Lombok,一时觉得很爽,但它却污染了你的代码,破坏了Java代码的完整性,可读性和安全性,同时还增加的团队的技术债务,这是一种弊大于利,得不偿失的操作。如果你确实想让自己的代码更加精炼,同时又兼顾可读性和编码效率,不妨使用主流的Scala或Kotlin这一基于JVM的语言。

    7ff5d7637ebfdec1dfa044876e70feb3.png

    总结

    Lombok本身是一个优秀的Java代码库,它采用了一种取巧的语法糖,简化了Java的编码,为Java代码的精简提供了一种方式,但在使用此代码库时,需要了解到Lombok并非一个标准的Java库。使用Lombok,会增加团队的技术债务,降低代码的可读性,增大代码的耦合度和调式难度。虽然在一定程度上Lombok减少了样板代码的书写,但也带来了一些未知的风险。如果你正在参与一个团队项目(或大型项目),考虑到后续的升级与扩展,是否使用Lombok,请与你的团队多沟通和三思。

    作者:ramostear
    原文:http://toutiao.com/i6820517160964588044
    展开全文
  • “ 去年在项目当中引入了 Lombok 插件,着实解放了双手,代替了一些重复的简单工作(Getter,Setter,toString 等方法的编写)。图片来自 Pexels但是,在使用的过程当中,也发现了一些坑,开始的时候并没有察觉到是 ...

    去年在项目当中引入了 Lombok 插件,着实解放了双手,代替了一些重复的简单工作(Getter,Setter,toString 等方法的编写)。

    d80c2abda0ba6760b4a6fd330c6a43f0.png图片来自 Pexels

    但是,在使用的过程当中,也发现了一些坑,开始的时候并没有察觉到是 Lombok 的问题,后来跟踪了对应的其他组件的源码,才发现是 Lombok 的问题!

    Setter-Getter 方法的坑

    问题发现

    我们在项目当中主要使用 Lombok 的 Setter-Getter 方法的注解,也就是组合注解 @Data,但是在一次使用 Mybatis 插入数据的过程当中,出现了一个问题。

    问题描述如下:
    我们有个实体类:
    @Data
    public class NMetaVerify{
        private NMetaType nMetaType;
        private Long id;
        ....其他属性
    }

    当我们使用 Mybatis 插入数据的时候,发现,其他属性都能正常的插入,但是就是 nMetaType 属性在数据库一直是 null。

    解决

    当我 Debug 项目代码到调用 Mybatis 的插入 SQL 对应的方法的时候,我看到 NMetaVerify 对象的 nMetaType 属性还是有数据的,但是执行插入之后,数据库的 nMetaType 字段就是一直是 null。

    原先我以为是我的枚举类型写法不正确,看了下别的同样具有枚举类型的字段,也是正常能插入到数据库当中的,这更让我感觉到疑惑了。

    于是,我就跟踪 Mybatis 的源码,发现 Mybatis 在获取这个 nMetaType 属性的时候使用了反射,使用的是 getxxxx 方法来获取的。

    但是我发现 nMetaType 的 get 方法好像有点和 Mybatis 需要的 getxxxx 方法长的好像不一样,问题找到了!

    原因

    Lombok 对于第一个字母小写,第二个字母大写的属性生成的 get-set 方法和 Mybatis 以及 idea 或者说是 Java 官方认可的 get-set 方法生成的不一样:
    #Lombok生成的Get-Set方法
    @Data
    public class NMetaVerify {
        private Long id;
        private NMetaType nMetaType;
        private Date createTime;

        public void lombokFound(){
            NMetaVerify nMetaVerify = new NMetaVerify();
            nMetaVerify.setNMetaType(NMetaType.TWO); //注意:nMetaType的set方法为setNMetaType,第一个n字母大写了,
            nMetaVerify.getNMetaType();                                  //getxxxx方法也是大写
        }
    }
    #idea,Mybatis,Java官方默认的行为为:
    public class NMetaVerify {
        private Long id;
        private NMetaType nMetaType;
        private Date createTime;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public NMetaType getnMetaType() {//注意:nMetaType属性的第一个字母小写
            return nMetaType;
        }

        public void setnMetaType(NMetaType nMetaType) {//注意:nMetaType属性的第一个字母小写
            this.nMetaType = nMetaType;
        }

        public Date getCreateTime() {
            return createTime;
        }

        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    }

    Mybatis(3.4.6 版本)解析 get-set 方法获取属性名字的源码:

    package org.apache.ibatis.reflection.property;

    import java.util.Locale;

    import org.apache.ibatis.reflection.ReflectionException;

    /**
     * @author Clinton Begin
     */

    public final class PropertyNamer {

            private PropertyNamer() {
                // Prevent Instantiation of Static Class
            }

            public static String methodToProperty(String name) {
                if (name.startsWith("is")) {//is开头的一般是bool类型,直接从第二个(索引)开始截取(简单粗暴)
                        name = name.substring(2);
                } else if (name.startsWith("get") || name.startsWith("set")) {//set-get的就从第三个(索引)开始截取
                        name = name.substring(3);
                } else {
                        throw new ReflectionException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
                }
                //下面这个判断很重要,可以分成两句话开始解释,解释如下
                //第一句话:name.length()==1
                //                      对于属性只有一个字母的,例如private int x;
                //                      对应的get-set方法是getX();setX(int x);
                //第二句话:name.length() > 1 && !Character.isUpperCase(name.charAt(1)))
                //                      属性名字长度大于1,并且第二个(代码中的charAt(1),这个1是数组下标)字母是小写的
                //                      如果第二个char是大写的,那就直接返回name
                if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
                        name = name.substring(01).toLowerCase(Locale.ENGLISH) + name.substring(1);//让属性名第一个字母小写,然后加上后面的内容
                }

                return name;
            }

            public static boolean isProperty(String name) {
                    return name.startsWith("get") || name.startsWith("set") || name.startsWith("is");
            }

            public static boolean isGetter(String name) {
                    return name.startsWith("get") || name.startsWith("is");
            }

            public static boolean isSetter(String name) {
                    return name.startsWith("set");
            }

    }

    Mybatis 解析 get-set 方法为属性名字测试:

        @Test
        public void foundPropertyNamer() {
            String isName = "isName";
            String getName = "getName";
            String getnMetaType = "getnMetaType";
            String getNMetaType = "getNMetaType";

            Stream.of(isName,getName,getnMetaType,getNMetaType)
                    .forEach(methodName->System.out.println("方法名字是:"+methodName+" 属性名字:"+ PropertyNamer.methodToProperty(methodName)));
        }

        #输出结果如下:
        方法名字是:isName 属性名字:name 
        方法名字是:getName 属性名字:name 
        方法名字是:getnMetaType 属性名字:nMetaType //这个以及下面的属性第二个字母都是大写,所以直接返回name
        方法名字是:getNMetaType 属性名字:NMetaType

    解决方案

    解决方案如下:

    • 修改属性名字,让第二个字母小写,或者说是规定所有的属性的前两个字母必须小写。

    • 如果数据库已经设计好,并且前后端接口对接好了,不想修改,那就专门为这种特殊的属性使用 idea 生成 get-set 方法。

    @Accessor(chain = true)注解的问题

    问题发现

    在使用 easyexcel(github.com/alibaba/eas…)导出的时候,发现以前的实体类导出都很正常,但是现在新加的实体类不正常了。

    比对了发现,新加的实体类增加了 @Accessor(chain = true)注解,我们的目的主要是方便我们链式调用 set 方法:
    new UserDto()
    .setUserName("")
    .setAge(10)
    ........
    .setBirthday(new Date());

    原因

    easyexcel 底层使用的是 cglib 来做反射工具包的:

    com.alibaba.excel.read.listener.ModelBuildEventListener 类的第130行
    BeanMap.create(resultModel).putAll(map);

    最底层的是cglibBeanMap的这个方法调用

    abstract public Object put(Object beanObject keyObject value);
    但是 cglib 使用的是 Java 的 rt.jar 里面的一个 Introspector 这个类的方法:
    # Introspector.java 第520行
    if (int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {
       pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), nullnull, method, null);
       //下面这行判断,只获取返回值是void类型的setxxxx方法
     } else if (void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {
        // Simple setter
        pd = new PropertyDescriptor(this.beanClass, name.substring(3), null, method);
        if (throwsException(method, PropertyVetoException.class)) {
           pd.setConstrained(true);
        }
    }

    解决方案

    解决方案如下:

    • 去掉 Accessor 注解。

    • 要么就等待 easyexcel 的作者替换掉底层的 cglib 或者是其他,反正是支持获取返回值不是 void 的 setxxx 方法就行。

    作者:liuxuzxx

    编辑:陶家龙

    出处:https://juejin.im/post/6881432532332576781

    65b4fcc26eefe73354879f735ed28ada.gif

    精彩文章推荐:

    干掉if-else,多点套路,少点弯路!新来个技术总监,禁止我们使用Lombok!我承认,要放弃使用Lombok了!
    展开全文
  • 来源:toutiao.com/i6820517160964588044如果您正在阅读此文,想必您对Project Lombok已经有了一段时间的了解...我承认,Lombok是一个很不错的Java库,它可以你在少写代码的同时耍耍酷,简单的几个注解,就可以干...

    来源:toutiao.com/i6820517160964588044


    如果您正在阅读此文,想必您对Project Lombok已经有了一段时间的了解。您是否正准备拥抱Lombok?还是正准备将如此酷炫的项目推荐给你的团队?如果您准备那么做,不妨听听我在使用Lombok一年后的一些感受。

    我承认,Lombok是一个很不错的Java库,它可以让你在少写代码的同时耍耍酷,简单的几个注解,就可以干掉一大片模板代码。但是,所有的源代码很多时候是用来阅读的,只有很少的时间是用来执行的(你可以细品这句话)。

    一年以前,我和大多数人都认为Lombok的出现会让Java的编码体验会更好,并极力的在我的团队中推荐使用Lombok。一年以后,我开始对此产生顾虑,尤其是在我准备为开源的博客系统Una-Boot升级Java版本时,我才意识到Lombok自己掉入了一个戏法陷阱。在我进一步分析其源代码并理解相关注解的工作原理后,发现我并不需要使用一个非标准的第三方库将Java转换为一个精巧而酷炫的语言。引入Lombok让我的项目一时爽,但一时爽的代价是随着项目推进,技术债务开始累积。

    接下来,我将用几个大家耳熟能详的场景,重演自己是如何掉入Lombok的戏法陷阱。

    爱的开始,恨的起源

    面对Lombok提供的诸多“神走位”,你并不会介意在IDE上新增一个插件。对于IntelliJ IDEA玩家而言,只需搜索“Lombok Plugin”便可找到这款神器并安装上它。爱上Lombok从安装Lombok插件开始,恨也从此萌芽。

    没使用Lombok之前,我们的源代码看起来是这一的:

    public class MyObject{
        private Long id;
        private String name;
        private int age;
        private int gender;

        public Long getId(){
            return id;
        }
        public void setId(Long id){
            this.id = id;
        }
        public String getName(){
            return name;
        }
        public void setName(String name){
            this.name = name;
        }
        public int getAge(){
            return age;
        }
        public void setAge(int age){
            this.age = age;
        }
        public int getGender(){
            return gender;
        }
        public void setGender(int gender){
            this.gender = gender;
        }

        @Override
        public boolean equals(Object o){
            if(this == o){
                return true;
            }
            if(o == null || getClass() != o.getClass()){
                return false;
            }
            MyObject obj =  (MyObject) o;
            return age = obj.age &&
                gender = obj.gender &&
                Objects.equals(id,obj.id) &&
                Objects.queals(name,obj.name);
        }

        @Override
        public int hashCode(){
            return Objects.hash(id,name,age,gender);
        }

        @Override
        public String toString(){
            return "MyObject{"+
                "id="+id+
                "name="+name+
                "age="+age+
                "gender="+gander+
                "}";
        }
    }
    2367dbaeebebd2bf1b8d4546ec941ecc.png

    每个JavaBean都会充斥着如上述getter,setter,equals,hashCode和toString的模板代码,这看起来像一个偏胖的人(不得不承认Java是一个有缺陷的编程语言)。当我们安装好Lombok插件后,IDE便可以识别其酷炫的注解,使用Lombok的@Getter和@Setter注解后,代码会像下面这样看起来很苗条:

    @Getter
    @Setter
    public class MyObject{
        private Long id;
        private String name;
        private int age;
        private int gender;

        @Override
        public boolean equals(Object o){
            if(this == o){
                return true;
            }
            if(o == null || getClass() != o.getClass()){
                return false;
            }
            MyObject obj =  (MyObject) o;
            return age = obj.age &&
                gender = obj.gender &&
                Objects.equals(id,obj.id) &&
                Objects.queals(name,obj.name);
        }

        @Override
        public int hashCode(){
            return Objects.hash(id,name,age,gender);
        }

        @Override
        public String toString(){
            return "MyObject{"+
                "id="+id+
                "name="+name+
                "age="+age+
                "gender="+gander+
                "}";
        }
    }

    你以为Lombok就这点能耐?它还能让你代码的“身材”更苗条,更魔鬼。上面的代码仍然还有改进的空间,我们可以用@EqualsAndHashCode注解替换到equals和hashCode方法:

    @Getter
    @Setter
    @EqualsAndHashCode
    public class MyObject{
        private Long id;
        private String name;
        private int age;
        private int gender;

        @Override
        public String toString(){
            return "MyObject{"+
                "id="+id+
                "name="+name+
                "age="+age+
                "gender="+gander+
                "}";
        }
    }

    现在的代码是否看起来爽多了?但这还不是最爽的时候。既然其他方法都替换掉了,那把toString方法也一起拿掉吧.如你所愿,可以使用@ToString注解去掉对于的方法:

    @Getter
    @Setter
    @EqualsAndHashCode
    @ToString
    public class MyObject{
        private Long id;
        private String name;
        private int age;
        private int gender;
    }

    经过Lombok的戏法之后,相比一开始的代码,看起来是不是很酷炫,很苗条,很性感?你以为到此为止了?远不止于此。你会发现类名上一大坨注解看起来好别扭,Lombok提供了一个组合注解@Data,可以替换掉类名头上那坨像翔一样的东西:

    @Data
    public class MyObject{
        private Long id;
        private String name;
        private int age;
        private int gender;
    }

    现在,Lombok是否让你的对象成为了你心目中完美的样子?魔鬼的“身材”,酷炫精炼。Lombok还有其他一些注解,如@Slf4j,@NoArgsConstructor,@AllArgsConstructor等等,介绍Lombok用法不是本文重点。

    a0528200ed2fbeb72a55367b98e3321f.png

    以上代码行数的变化过程,也许是无数程序员爱上Lombok的主要原因吧,这就像一个肥胖的人逐渐变成一个身材苗条的人。同时也让你看到了一个现象:你以为程序员很懒吗?其他有些时候他们比你想象中的还要懒。在爽的同时,也为代码种下了祸根。

    扭曲的审美,爱的隐患

    扭曲的审美,导致了被审视的对象处于亚健康状态。


    使用Lombok插件之后,我们的代码也处于“亚健康”状态。还是回归一开始的那句话:所有的源代码很多时候是用来阅读的,只有很少的时间是用来执行的。

    本质上讲,我们都追求减少程序中的样板代码以使其代码更精炼简洁,从而提高代码的可读性和可维护性。

    但Lombok并没有达到我们所追求的这一愿景,它仅仅是利用Java语言在编译时的空档期,使用一种很取巧的方式,将我们所需要的方法注入(写入)到当前的类中,这种过程很像在hack我们的代码,只是一种看起来酷炫的把戏。

    这种把戏并不智能和安全,反而会破坏Java代码现有的特性以及代码的可读性。下面,结合我自己使用Lombok之后的感受,谈谈Lombok带来的几大痛点。

    1. JDK版本问题

    当我想要将现有项目的JDK从Java 8升级到Java 11时,我发现Lombok不能正常工作了。于是我不得不将所有的Lombok注解从项目源代码中清除,并使用IDE自带的功能生成getter/setter,equals,hashCode,toString以及构造器等方法,你也可以使用Delombok工具完成这一过程。但这终究会消耗你很多的时间。

    2. 胁迫使用

    当你的源代码中使用了Lombok,恰好你的代码又被其他的人所使用,那么依赖你代码的人,也必须安装Lombok插件(不管他们喜不喜欢),同时还要花费时间去了解Lombok注解的使用情况,如果不那么做,代码将无法正常运行。使用过Lombok之后,我发现这是一种很流氓的行为。

    3. 可读性差

    Lombok隐藏了JavaBean封装的细节,如果你使用@AllArgsConstructor注解,它将提供一个巨型构造器,让外界有机会在初始化对象时修改类中所有的属性。

    首先,这是极其不安全的,因为类中某系属性我们是不希望被修改的;

    另外,如果某个类中有几十个属性存在,就会有一个包含几十个参数的构造器被Lombok注入到类中,这是不理智的行为;

    其次,构造器参数的顺序完全由Lombok所控制,我们并不能操控,只有当你需要调试时才发现有一个奇怪的“小强”在等着你;

    最后,在运行代码之前,所有JavaBean中的方法你只能想象他们长什么样子,你并不能看见。

    4. 代码耦合度增加

    当你使用Lombok来编写某一个模块的代码后,其余依赖此模块的其他代码都需要引入Lombok依赖,同时还需要在IDE中安装Lombok的插件。


    虽然Lombok的依赖包并不大,但就因为其中一个地方使用了Lombok,其余所有的依赖方都要强制加入Lombok的Jar包,这是一种入侵式的耦合,如果再遇上JDK版本问题,这将是一场灾难。

    5. 得不偿失

    使用Lombok,一时觉得很爽,但它却污染了你的代码,破坏了Java代码的完整性,可读性和安全性,同时还增加的团队的技术债务,这是一种弊大于利,得不偿失的操作。如果你确实想让自己的代码更加精炼,同时又兼顾可读性和编码效率,不妨使用主流的Scala或Kotlin这一基于JVM的语言。

    ecb294954178ff0e3ae67b6d80e397a5.png

    总结

    Lombok本身是一个优秀的Java代码库,它采用了一种取巧的语法糖,简化了Java的编码,为Java代码的精简提供了一种方式,但在使用此代码库时,需要了解到Lombok并非一个标准的Java库。使用Lombok,会增加团队的技术债务,降低代码的可读性,增大代码的耦合度和调式难度。虽然在一定程度上Lombok减少了样板代码的书写,但也带来了一些未知的风险。如果你正在参与一个团队项目(或大型项目),考虑到后续的升级与扩展,是否使用Lombok,请与你的团队多沟通和三思。

    1933243f2c8df0dd267377b09277e8c1.png以下资料关注公众号,回复【8888】,即可免费获取。ab8c53c0f20abcb9103eb49729159dcb.png

    福利时刻

    8a8bffc46c9945c6961dae289c1207e8.png

    cf5bfe27f8f8c176e267a061e7feeb29.png


    展开全文
  • 不得承认,Lombok 是一个很不错的 Java 库,它可以你在少写代码的同时耍耍酷,简单的几个注解,就可以干掉一大片模板代码。但是,所有的源代码很多时候是用来阅读的,只有很少的时间是用来执行的 (你可以细品这...
  • 点击上方一个优秀的废人,选择设星标优质文章,及时送达巨人的肩膀:ramostear.com/blog/2020/04/28/uk1860p8.htmlLombok不得承认,Lombok 是一个很不错的 Java 库,它可以你在少写代码的同时耍耍酷,简单的几...
  • 通俗一些讲,就是原来需要写的许多的getter、setter、equals、构造方法等,需要再写了。正是这些懒到极致的特性,导致大批的Java开发工程师使用该库,并奉若神明,毕竟可以少写代码,早点下班,简直不要太方便。...
  • Java面试笔试面经、Java技术每天学习一点公众号Java面试关注我迷路作者:ramostear来源:https://www.toutiao.com/i682051716096458...
  • 这是为什么呢?之前去龙目岛拍的日落。2 Lombok提供的便利一般我们在Java中用到POJO时,就很容易想到要用Lombok,如VO、DTO、DO等。使用Lombok需要安装对应IDE的插件,同时需要引入依赖:org.projectlombok...
  • 前言 最近上网查资料发现很多人对lombok褒贬不一,引起了我的兴趣,因为我们项目中也在大量使用lombok,大家不同的观点我也困惑了几天,今天结合...为什么建议使用lombok? 1.传统javabean 在没使用lombok之前,我们
  • 这是为什么呢? 之前去龙目岛拍的日落。 2 Lombok提供的便利 一般我们在Java中用到POJO时,就很容易想到要用Lombok,如VO、DTO、DO等。使用Lombok需要安装对应IDE的插件,同时需要引入依赖: <dependency> &...
  • 点击上方Java后端,选择设星标优质文章,及时送达这两天关于 Lombok 的文章层出不穷,众说纷纭,那么到底是该呢?先说利好先说一下它可以做什么,最简单的用法,帮助我们生成...
  • Lombok

    2020-06-30 14:04:16
    新来的同事不会 Lombok,所以会引发...然后我和他说出了问题所在,他安装下 Lombok 插件再重新编译下,他居然和我说知道什么插件,感觉他没用过吧,甚至都没有听说过。 好吧,我认了,我默默亲自他把 Lombok
  • lombok相信大家都在lombok提供了一系列的注解,可以我们减少很多重复性的代码量,方便我们快速开发应用程序。比如:在model类上使用@Data,就不用再写get/set方法。同样,lombok还为对象...为什么加了@Slf4...

空空如也

空空如也

1 2 3
收藏数 52
精华内容 20
关键字:

为什么不让用lombok