Lombok快速入门

Lombok介绍:

  • Lombok其实就是取名自龙目岛(Pulau Lombok),龙目岛是印度尼西亚西努沙登加拉(Nusa Tenggara Barat)省岛屿,西隔龙目海峡面对巴厘岛,东隔阿拉斯(Alas)海峡面松巴哇(Sumbawa)岛,北濒爪哇海,南临印度洋。
  • 在编程上,Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法。简而言之,一句话就是:通过简单的注解来精简代码达到消除冗长代码的目的。
  • Lombok官网
  • github地址


Lombok优点:

  • 提高编码效率
  • 使代码更简洁
  • 消除冗长代码
  • 避免修改字段名字时忘记修改方法名

注:IDE上必须要支持Lombok,否则IDE会报错。

为什么说Lombok可以使代码更简洁、可以消除冗长代码呢?我们来拿lombok官网的一个例子来说:

public class Mountain{
    private String name;
    private double longitude;
    private String country;
}

要使用这个对象,必须还要写一些getter和setter方法,可能还要写一个构造器、equals方法、或者hash方法。这些方法很冗长而且没有技术含量,我们叫它样板式代码。

lombok的主要作用是通过一些注解,消除样板式代码,像这样:

@Data
public class Mountain{
    private String name;
    private double longitude;
    private String country;
}

然后可以看到这个类自动生成了这些方法:

如果觉得@Data这个注解有点简单粗暴的话,Lombok提供一些更精细的注解,比如@Getter、@Setter,(这两个是field注解),@ToString,@AllArgsConstructor(这两个是类注解)。这些可能是最常见的用法,更详细的用法可以参考[Lombok feature]overview(https://projectlombok.org/features/)

Lombok既是一个IDE插件,也是一个项目要依赖的jar包。Lombok是依赖jar包的原因是因为编译时要用它的注解。是插件的原因是他要在编译器编译时通过操作AST(抽象语法树)改变字节码生成。也就是说他可以改变java语法.。他不像spring的依赖注入或者hibernate的orm一样是运行时的特性,而是编译时的特性。



Lombok原理:

  • Lombok 实现了 JSR 269 Pluggable Annotation Processing API 规范,也就是可插拔注释处理
  • javac 从 JDK6 开始支持 “JSR 269 API” 规范
  • 只要程序实现了该API,就能在javac运行的时候得到调用
  • 而Lombok实现了 “JSR 269 API” 规范 ,在编译时,javac编译源码的具体流程如下:

1.javac对源代码(Source File)进行分析(Parse),生成一棵抽象语法树(AST)
2.运行过程(Annotation Processing)中调用实现了 "JSR 269 API" 的Lombok程序(Lombok Annotation Processor)
3.此时Lombok就对第一步骤得到的AST进行处理(Lombok Annotation Handler),找到@Data注解所在类对应的语法树(AST),然后修改该语法树(AST),增加getter和setter方法定义的相应树节点
4.javac使用修改后的抽象语法树(Modified AST)进行分析生成(Analyze and Generate)字节码文件(Byte Code)



添加Lombok到项目中

创建一个Maven项目,通过pom.xml配置Lombok依赖到项目中,配置依赖如下:

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


IDEA安装Lombok插件

然后还需要在IDE中安装Lombok插件,我这里使用的是IDEA,所以先以IDEA为例做演示。点击右上角的 File -> setting -> Plugins :

搜索Lombok Plugin进行安装:

安装完成后,重启IDEA:



Eclipse安装Lombok插件:

1.安装该插件时最好关闭Eclipse,然后在官网中下载lombok.jar,下载地址

2.将 lombok.jar 放在eclipse安装目录下,和 eclipse.ini 文件平级的。

3.双击运行 lombok.jar

如果没法直接双击运行的话,就在 lombok.jar 的目录下,打开cmd命令行,运行如下命令:

java -jar lombok.jar

如果以下提示的权限问题则使用管理员身份运行即可:

注:Mac/Linux 系统下则使用 sudo java -jar lombok.jar 命令进行运行即可,但是要确保执行用户有sudo权限。

成功运行后会弹框如下框,一开始可能会加载些东西,加载完成后界面如下:

安装成功后如下图:

打开Eclipse,看看是否已安装Lombok插件,如下则是安装成功:



Lombok注解

Lombok 常用的注解:

注解 描述
@Getter / @Setter 可以作用在类上和属性上,放在类上,会对所有的非静态(non-static)属性生成Getter/Setter方法,放在属性上,会对该属性生成Getter/Setter方法。并可以使用该注解中的AccessLevel属性来指定Getter/Setter方法的访问级别。
@ToString 生成toString方法,默认情况下,会输出类名、所有属性,属性会按照顺序输出,以逗号分割。可以使用该注解中的exclude属性来指定生成的toSpring方法不包含对象中的哪些字段,或者使用of属性来指定生成的toSpring方法只包含对象中的哪些字段
@EqualsAndHashCode 默认情况下,会使用所有非瞬态(non-transient)和非静态(non-static)字段来生成equals和hascode方法,也可以使用exclude或of属性。
@NoArgsConstructor 生成无参构造器
@RequiredArgsConstructor 会生成一个包含标识了@NonNull注解的变量的构造方法。生成的构造方法是private,如果想要对外提供使用的话,可以使用staticName选项生成一个static方法。
@AllArgsConstructor 生成全参构造器,当我们需要重载多个构造器的时候,Lombok就无能为力了。
@Slf4j 该注解是用来解决不用每次都写 private final Logger logger = LoggerFactory.getLogger(XXX.class); 这句代码的。使用的日志框架是LogBack
@Log4j 该注解也是用来解决不用每次都写日志对象声明语句的,从字面上也可以看出,使用的日志框架是log4j
@Data 该注解是 @ToString、@EqualsAndHashCode注解,和所有属性的@Getter注解, 以及所有non-final属性的@Setter注解的组合,通常情况下,我们使用这个注解就足够了。


反编译大法

当我们想查看.class文件的源码时,可以使用Java反编译工具:

  • Java Decompiler
  • JD 官网地址
  • 分为以下几类
    • JD-GUI,独立的图形化软件
    • JD-Eclipse,可以集成到Eclipse插件
    • JD-Intellij,可以集成到IDEA插件

这里提到反编译工具的原因是因为Lombok是编译时修改的抽象语法树,所以我们想查看编译后的.class文件的源码就需要使用反编译工具。这里所介绍到的 Java Decompiler 就是用来帮助我们在使用Lombok遇到问题时,去验证编译后的.class文件的。



使用Lombok时需要注意的点

  • 在类需要序列化、反序列化时或者需要详细控制字段时,应该谨慎考虑是否要使用Lombok,因为在这种情况下容易出问题。例如:Jackson、Json 序列化
  • 使用Lombok虽然能够省去手动创建setter和getter方法等繁琐事情,但是却降低了源代码文件的可读性和完整性,减低了阅读源代码的舒适度
  • 使用@Slf4j还是@Log4j注解,需要根据实际项目中使用的日志框架来选择。
  • Lombok并非处处适用,我们需要选择适合的地方使用Lombok,例如pojo是一个好地方,因为pojo很单纯

Lombok实战

我这里拿之前项目中的一个 Category 类来做为演示的例子,在使用Lombok之前,这个类里是写了getter setter方法以及构造函数的。现在我们使用Lombok将代码改造如下:

package org.mmall.pojo;

import lombok.*;

import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
@ToString(exclude = "updateTime")
public class Category {
    private Integer id;

    private Integer parentId;

    private String name;

    private Boolean status;

    private Integer sortOrder;

    private Date createTime;

    private Date updateTime;

}

编译后生成的代码如下,使用反编译工具进行查看:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.mmall.pojo;

import java.beans.ConstructorProperties;
import java.util.Date;

public class Category {
    private Integer id;
    private Integer parentId;
    private String name;
    private Boolean status;
    private Integer sortOrder;
    private Date createTime;
    private Date updateTime;

    public Integer getId() {
        return this.id;
    }

    public Integer getParentId() {
        return this.parentId;
    }

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

    public Boolean getStatus() {
        return this.status;
    }

    public Integer getSortOrder() {
        return this.sortOrder;
    }

    public Date getCreateTime() {
        return this.createTime;
    }

    public Date getUpdateTime() {
        return this.updateTime;
    }

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

    public void setParentId(Integer parentId) {
        this.parentId = parentId;
    }

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

    public void setStatus(Boolean status) {
        this.status = status;
    }

    public void setSortOrder(Integer sortOrder) {
        this.sortOrder = sortOrder;
    }

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

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public Category() {
    }

    @ConstructorProperties({"id", "parentId", "name", "status", "sortOrder", "createTime", "updateTime"})
    public Category(Integer id, Integer parentId, String name, Boolean status, Integer sortOrder, Date createTime, Date updateTime) {
        this.id = id;
        this.parentId = parentId;
        this.name = name;
        this.status = status;
        this.sortOrder = sortOrder;
        this.createTime = createTime;
        this.updateTime = updateTime;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Category)) {
            return false;
        } else {
            Category other = (Category)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$id = this.getId();
                Object other$id = other.getId();
                if (this$id == null) {
                    if (other$id != null) {
                        return false;
                    }
                } else if (!this$id.equals(other$id)) {
                    return false;
                }

                return true;
            }
        }
    }

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

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

    public String toString() {
        return "Category(id=" + this.getId() + ", parentId=" + this.getParentId() + ", name=" + this.getName() + ", status=" + this.getStatus() + ", sortOrder=" + this.getSortOrder() + ", createTime=" + this.getCreateTime() + ")";
    }
}

如上,从反编译后的代码可以看到,getter setter方法和无参、全参构造器以及equals、hashcode、toString方法都生成出来了。在@EqualsAndHashCode注解中我们使用of属性指定只对比对象中id这个字段,所以生成的equals和hashcode只使用id这个字段作为因子,默认不指定的情况下是使用对象中所有的字段作为因子。而在@ToString注解中,我们使用exclude属性指定updateTime这字段不被输出,所以Lombok生成的toString方法中没有包含updateTime这个字段。

我们再来演示一下@Getter、@Setter以及@RequiredArgsConstructor注解的使用,新建一个测试类,编辑代码如下:

package org.mmall.pojo;

import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@RequiredArgsConstructor(staticName = "getInstance")
public class Test {
    private String name;

    @NonNull
    private int age;
}

编译后生成的代码如下,使用反编译工具进行查看:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.mmall.pojo;

import java.beans.ConstructorProperties;
import lombok.NonNull;

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

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

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

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

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

    @ConstructorProperties({"age"})
    private Test(@NonNull int age) {
        this.age = age;
    }

    public static Test getInstance(@NonNull int age) {
        return new Test(age);
    }
}

可以看到,@RequiredArgsConstructor注解会生成一个包含标识了@NonNull注解的变量的构造方法,并且生成的构造方法是private的,使用staticName选项可以生成一个可以得到该对象实例的static方法。

接下来演示一下@Slf4j注解的使用,因为我项目中使用的是logback,所以使用@Slf4j注解,如果使用的是log4j,则使用@Log4j注解,两者的使用方式是一样的。代码如下:

...
@Service("iCategoryService")
@Slf4j
public class CategoryServiceImpl implements ICategoryService {

    public ServerResponse<List<Category>> getChildrenParallelCategory(Integer categoryId) {
        List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId);
        if (CollectionUtils.isEmpty(categoryList)) {
            log.info("未找到当前分类的子分类");
        }
        return ServerResponse.createBySuccess(categoryList);
    }
}

编译后生成的代码如下,使用反编译工具进行查看:

...
@Service("iCategoryService")
public class CategoryServiceImpl implements ICategoryService {

    private static final Logger log = LoggerFactory.getLogger(CategoryServiceImpl.class);

    public ServerResponse<List<Category>> getChildrenParallelCategory(Integer categoryId) {
        List<Category> categoryList = this.categoryMapper.selectCategoryChildrenByParentId(categoryId);
        if (CollectionUtils.isEmpty(categoryList)) {
            log.info("未找到当前分类的子分类");
        }
        return ServerResponse.createBySuccess(categoryList);
    }
}

可以看到,Lombok会自动帮我们生成log对象的声明代码,这样我们就不需要总是每个类都去写这句代码了。

原文地址:http://blog.51cto.com/zero01/2112466

时间: 2024-10-08 23:12:34

Lombok快速入门的相关文章

Elastic-Job快速入门

1 Elastic-Job快速入门1.1 环境搭建1.1.1.版本要求JDK要求1.7及以上版本Maven要求3.0.4及以上版本zookeeper要求采用3.4.6及以上版本1.1.2.Zookeeper安装&运行https://archive.apache.org/dist/zookeeper/ 下载某版本Zookeeper,并解压.安装可以查看博客:https://www.cnblogs.com/dalianpai/p/12057064.html 1.1.3.创建maven工程创建mave

springboot2.0整合freemarker快速入门

目录 1. 快速入门 1.1 创建工程pom.xml文件如下 1.2 编辑application.yml 1.3 创建模型类 1.4 创建模板 1.5 创建controller 1.6 测试 2. FreeMarker 基础 2.1 数据模型 2.2 List指令 2.3 遍历Map数据 2.4 if指令 2.5 运算符 2.6 空值处理 2.7 内建函数 freemarker是一个用Java开发的模板引擎 常用的java模板引擎还有哪些? Jsp.Freemarker.Thymeleaf .V

笔记:Spring Cloud Zuul 快速入门

Spring Cloud Zuul 实现了路由规则与实例的维护问题,通过 Spring Cloud Eureka 进行整合,将自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获取了所有其他微服务的实例信息,这样的设计非常巧妙的将服务治理体系中维护的实例信息利用起来,使得维护服务实例的工作交给了服务治理框架自动完成,而对路由规则的维护,默认会将通过以服务名作为 ContextPath 的方式来创建路由映射,也可以做一些特别的配置,对于签名校验.登录校验等在微服务架构中的冗余问题

javaweb-html快速入门

本文主要是进行HTML简单介绍(详细的属性查帮助文档就行了,这里主要为快速入门,赶时间,在最短的时间中看明白一个html文件的代码(如果能称之为代码的话)详细的样式表,布局啥的有时间再研究吧) HTML 1.html的简介 1.1,html的全称:HyperText Mark-up Language ,超文本标记型语言,是网页的语言. 超文本:比文本更加强大(后面还会讲到XML,可扩展标记性语言) 标记:就是标签,html所有操作都是通过标签直接或间接的操作(把需要操作的数据通过标签封装起来)

crosswalk 快速入门,利用WebRTC(html)开始开发视频通话

crosswalk 快速入门,利用WebRTC(html)开始开发视频通话 安装Python 从http://www.python.org/downloads/ 下载安装程序 安装完后,再添加到环境变量. 安装Oracle JDK 下载页面: http://www.oracle.com/technetwork/java/javase/downloads/ 选择要下载的Java版本(推荐Java 7). 选择一个JDK下载并接受许可协议. 一旦下载,运行安装程序. 安装Ant Ant:下载http

bash编程快速入门

首先,我们简单的介绍一下bash,bash是GNU计划编写的Unixshell,它是许多Linux平台上的内定shell,它提供了用户与系统的很好的交互,对于系统运维人员,bash的地位是举足轻重的,bash编程能很快处理日常的任务 bash入门,一个最简单的bash例子 #vim hello.sh #!/bin/bash #This is the first example of the bash #echo "Hello world" 下面,我们就这个简单的bash 脚本来介绍一下

定时器(Quartz)快速入门

Quartz概述 Quartz中的触发器 Quartz中提供了两种触发器,分别是CronTrigger和SimpleTrigger. SimpleTrigger 每 隔若干毫秒来触发纳入进度的任务.因此,对于夏令时来说,根本不需要做任何特殊的处理来"保持进度".它只是简单地保持每隔若干毫秒来触发一次,无论你的 SimpleTrigger每隔10秒触发一次还是每隔15分钟触发一次,还是每隔24小时触发一次. CronTrigger 在特定"格林日历"时刻触发纳入进程的

vue.js--60分钟快速入门

Vue.js--60分钟快速入门 Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的.相比于Angular.js,Vue.js提供了更加简洁.更易于理解的API,使得我们能够快速地上手并使用Vue.js. 本文摘自:http://www.cnblogs.com/keepfool/p/5619070.html 如果你之前已经习惯了用jQuery操作DOM,学习Vue.js时请先抛开手动操作DOM的思维,因为Vue.js是数据驱动的,你无需手动操作DOM

Netty5快速入门及实例视频教程(整合Spring)

Netty5快速入门及实例视频教程+源码(整合Spring) https://pan.baidu.com/s/1pL8qF0J 01.传统的Socket分析02.NIO的代码分析03.对于NIO的一些疑惑04.Netty服务端HelloWorld入门05.Netty服务端入门补充06.Netty客户端入门07.如何构建一个多线程NIO系统08.Netty源码分析一09.Netty源码分析二10.Netty5服务端入门案例11.Netty5客户端入门案例12.单客户端多连接程序13.Netty学习