V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hansonwang99
V2EX  ›  推广

SpringBoot 优雅编码之: Lombok 加持

  •  
  •   hansonwang99 · 2018-04-09 07:19:54 +08:00 · 4562 次点击
    这是一个创建于 2201 天前的主题,其中的信息可能已经有所发展或是发生改变。

    小米游戏本


    概述

    Lombok 通过提供简单的语法注解形式来帮助简化消除一些必须有但显得很臃肿的 java 代码。典型的是对于 POJO 对象的简化(如自动帮我们生成 Setter 和 Getter 等),有了 Lombok 的加持,开发人员可以免去很多重复且臃肿的操作,极大地提高 java 代码的信噪比,因此我们必须尝试并应用起来!


    IntelliJ IDEA 上配置

    方法一:直接在 IDEA 界面中配置

    • 首先进入 Plugins 界面:

    进入 Plugins 界面

    • 然后搜索并安装 Lombok 插件:

    安装 Lombok 插件

    • 最后不要忘了开启 Annotation Processors 的 Enable 选项:

    Enable Annotation Processors

    上述安装完成以后需要重启 IDEA 生效!


    方法二:手动下载 Lombok 插件安装

    有时由于网络原因,上面方法一这种方式安装失败,因此只能手动下载安装

    选择 lombok 的 zip 包来安装

    • 重启 idea 即可

    重启 IDEA 生效

    IDE 中设置完成以后需要在 pom.xml 中添加如下所示的 lombok 依赖才能使用

    <dependency>
    	<groupId>org.projectlombok</groupId>
    	<artifactId>lombok</artifactId>
    	<version>1.16.16</version>
    </dependency>
    

    Lombok 主要注解

    • @Getter and @Setter / 自动为属性提供 Set 和 Get 方法
    • @ToString / 该注解的作用是为类自动生成 toString()方法
    • @EqualsAndHashCode / 为对象字段自动生成 hashCode 和 equals 实现
    • @AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor / 顾名思义,为类自动生成对应参数的 constructor
    • @Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog / 自动为类添加对应的 log 支持
    • @Data / 自动为所有字段添加 @ToString, @EqualsAndHashCode, @Getter,为非 final 字段添加 @Setter,和 @RequiredArgsConstructor,本质上相当于几个注解的综合效果
    • @NonNull / 自动帮助我们避免空指针。作用在方法参数上的注解,用于自动生成空值参数检查
    • @Cleanup / 自动帮我们调用 close()方法。作用在局部变量上,在作用域结束时会自动调用 close 方法释放资源

    下文就 Lombok 中用的最为频繁的@Data@Log注解进行代码实战!


    @Data 注解使用

    官网关于 @Data 注解的解释如下:

    All together now: A shortcut for @ToString, @EqualsAndHashCode, @Getter on all fields, @Setter on all non-final fields, and @RequiredArgsConstructor!

    不难理解,其可以看成是多个 Lombok 注解的集成,因此使用很方便!

    • 先来创建一个 POJO 实体 UserLombok,普通的写法如下:
    public class UserLombok {
      private final String name;
      private int age;
      private double score;
      private String[] tags;
      
      public UserLombok(String name) {
        this.name = name;
      }
      
      public String getName() {
        return this.name;
      }
      
      void setAge(int age) {
        this.age = age;
      }
      
      public int getAge() {
        return this.age;
      }
      
      public void setScore(double score) {
        this.score = score;
      }
      
      public double getScore() {
        return this.score;
      }
      
      public String[] getTags() {
        return this.tags;
      }
      
      public void setTags(String[] tags) {
        this.tags = tags;
      }
      
      @Override public String toString() {
        return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + “)”;
      }
      
      protected boolean canEqual(Object other) {
        return other instanceof DataExample;
      }
      
      @Override public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof DataExample)) return false;
        DataExample other = (DataExample) o;
        if (!other.canEqual((Object)this)) return false;
        if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
        if (this.getAge() != other.getAge()) return false;
        if (Double.compare(this.getScore(), other.getScore()) != 0) return false;
        if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
        return true;
      }
      
      @Override public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final long temp1 = Double.doubleToLongBits(this.getScore());
        result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
        result = (result*PRIME) + this.getAge();
        result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
        result = (result*PRIME) + Arrays.deepHashCode(this.getTags());
        return result;
      }
    }
    
    • Lombok 加持后,写法可简化为:
    @Data
    public class UserLombok {
        private final String name;
        private int age;
        private double score;
        private String[] tags;
    }
    

    在 IDEA 中使用时,Lombok 的注解会自动补全,如下图所示:

    Lombok 注解自动补全

    • 我们来写 POJO 的测试代码
        public static void main( String[] args ) {
            UserLombok userLombok = new UserLombok("hansonwang99 ”);
            userLombok.setAge(18);
            String[] array = new String[]{"apple","juice ”};
            userLombok.setTags( array );
            userLombok.setScore( 99.0 );
            System.out.println(userLombok);
        }
    

    由下图我们可以看到 IDEA 依然可以自动为我们补全由 Lombok 自动生成的代码:

    自动生成的代码

    • 结果打印

    由于 Lombok 为我们自动生成了 toString 方法,因此对象的打印结果如下:

    UserLombok(name=hansonwang99, age=18, score=99.0, tags=[apple, juice])
    

    @Log 注解实战

    在我的文章 Spring Boot 日志框架实践 一文中,我们使用 Log4j2 来作为日志对象,其写法如下:

    @RestController
    @RequestMapping("/testlogging ”)
    public class LoggingTestController {
    
        private final Logger logger = LogManager.getLogger(this.getClass());
    
        @GetMapping("/hello ”)
        public String hello() {
            for(int i=0;i<10_0000;i++){
                logger.info("info execute index method ”);
                logger.warn("warn execute index method ”);
                logger.error("error execute index method ”);
    
            }
    
            return "My First SpringBoot Application ”;
        }
    }
    

    若改用 Lombok 后,写法变得更加简洁,我们只需要引入对应的 @Log 注解即可完成 log 对象的生成:

    @RestController
    @RequestMapping("/testloggingwithlombok ”)
    @Log4j2
    public class LoggingTestControllerLombok {
    
        @GetMapping("/hello ”)
        public String hello() {
            for(int i=0;i<10_0000;i++){
                log.info("info execute index method ”);
                log.warn("warn execute index method ”);
                log.error("error execute index method ”);
    
            }
    
            return "My First SpringBoot Application ”;
        }
    }
    

    怎么样,是不是一切都是那么地优雅!


    后记

    更多关于 SpringBoot 的文章:


    CodeSheep

    28 条回复    2018-04-26 15:15:19 +08:00
    youngxhui
        1
    youngxhui  
       2018-04-09 07:29:19 +08:00 via Android
    感谢分享,不过我选择 kotlin😂
    kimown
        2
    kimown  
       2018-04-09 07:29:42 +08:00   ❤️ 1
    换 kotlin 吧,java 已经没人用了(逃)
    boywang004
        3
    boywang004  
       2018-04-09 08:01:51 +08:00
    换 kotlin 吧!别 lombok 了……
    johnniang
        4
    johnniang  
       2018-04-09 08:05:00 +08:00 via Android
    难道不觉得这样维护起来很麻烦吗
    sagaxu
        5
    sagaxu  
       2018-04-09 08:22:39 +08:00 via Android
    这就是 kotlin 的 data class
    Troevil
        6
    Troevil  
       2018-04-09 08:27:10 +08:00
    对于没装 lombok 插件的人来说就是噩梦 满屏的错误
    asj
        7
    asj  
       2018-04-09 08:27:35 +08:00   ❤️ 2
    这跟 Spring Boot 有一毛钱关系么?
    tedzhou1221
        8
    tedzhou1221  
       2018-04-09 08:38:27 +08:00 via Android
    我选择 idea 快捷键生成,哈哈
    fengdianxun
        9
    fengdianxun  
       2018-04-09 08:47:57 +08:00
    lombok 要求协同开发都要装这个插件,我选择 kotlin
    loongwang
        10
    loongwang  
       2018-04-09 09:02:20 +08:00
    用了很久了.很好用.关键是修改字段很方便,不用再去管 get/set 了
    lrh3321
        11
    lrh3321  
       2018-04-09 09:08:08 +08:00 via Android
    感谢分享,不过我已经改用 kotlin 了。
    applehater
        12
    applehater  
       2018-04-09 09:08:32 +08:00 via iPhone   ❤️ 1
    @youngxhui 没有人用 Groovy 吗,Kotlin 语法呀混淆,难受。
    timothyye
        13
    timothyye  
       2018-04-09 09:09:48 +08:00 via Android
    面向注解编程,哈哈
    lxguidu
        14
    lxguidu  
       2018-04-09 09:15:12 +08:00
    这自己都可以实现
    neoblackcap
        15
    neoblackcap  
       2018-04-09 09:33:05 +08:00
    没有装插件的人都报错了,而且毕竟都不是自己写的,我还是倾向于一眼就可以看出来发生了什么的 getter/setter 写法。而且还不是生成的,又不费劲。
    DrJoseph
        16
    DrJoseph  
       2018-04-09 09:37:45 +08:00
    在团队没有普及 Lombok 之前,还是老老实实自动生成吧
    letitbesqzr
        17
    letitbesqzr  
       2018-04-09 09:45:54 +08:00
    @kimown #2 请问是哪里来的结论 java 没人用了。
    notreami
        18
    notreami  
       2018-04-09 09:47:03 +08:00
    Lombok 不错,已经在使用了,github 上,我见过的项目,没几个不用的。
    这种装个插件都搞不定,jdk 是不是也是麻烦别人给装的?

    kotlin 这种,3 年前,Scala 也很装逼。现在也凉了。。。再过 3 年,kotlin 还热嘛?
    q397064399
        19
    q397064399  
       2018-04-09 09:53:18 +08:00
    @neoblackcap #15 修改字段属性或者名字之后,需要重新生成一次,挺麻烦的
    gangsta
        20
    gangsta  
       2018-04-09 09:53:41 +08:00
    @kimown
    4 月的 tiobe 排名:
    mgcnrx11
        21
    mgcnrx11  
       2018-04-09 10:06:18 +08:00 via iPhone
    说到 kotlin 在 eclipse 不用装插件一样(逃
    night98
        22
    night98  
       2018-04-09 10:10:25 +08:00   ❤️ 1
    还可以用 groove 写 pojo,哈哈,也不用写 get set 方法,maven 加入依赖即可编译运行,idea 自动支持。
    paragon
        23
    paragon  
       2018-04-09 10:11:57 +08:00
    @neoblackcap 无法同意得更多 其实不装插件也不会影响编译打包的~
    laodao1990
        24
    laodao1990  
       2018-04-09 12:55:41 +08:00 via iPhone
    上次有人推广这玩意就有人吵起来了,可以翻翻 v2
    woscaizi
        25
    woscaizi  
       2018-04-09 14:42:59 +08:00
    用过一阵子,后来还是老老实实的写 getter and setter 了,毕竟不能保证每个开发者都安装 lombok 插件。
    jorneyr
        26
    jorneyr  
       2018-04-09 21:55:35 +08:00
    我们在环境搭建的文档里已经要求安装 Lombok 插件,就是一个文档规范的问题,写清楚环境搭建的流程,照文档都不好好做的话,还能有啥期望。
    Klingon
        27
    Klingon  
       2018-04-10 10:34:49 +08:00
    已经在老老实实写 getter setter,[逃]
    jack80342
        28
    jack80342  
       2018-04-26 15:15:19 +08:00
    这几天翻译了最新的 Spring boot 官方文档,https://www.gitbook.com/book/jack80342/spring-boot/details
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1148 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 65ms · UTC 18:25 · PVG 02:25 · LAX 11:25 · JFK 14:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.