专栏首页aoho求索Lombok使用与原理

Lombok使用与原理

Lombok使用与原理

1. Lombok简介

首先 Lombok是一款Java IDE的应用工具插件,一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,比如属性的构造器、getter、setter、equals、hashcode、toString方法。结合IDE,通过使用对应的注解,可以在编译源码的时候生成对应的方法。官方地址: https://projectlombok.org/

虽然上述的那些常用方法IDE都能生成,但是lombok更加简洁与方便,能够达到的效果就是在源码中不需要写一些通用的方法,但是在编译生成的字节码文件中会帮我们生成这些方法,这就是lombok的神奇作用。

2. 安装

2.1 插件安装

笔者主要使用的IDE是Intellij idea,编译器需要在

preference->plugins->Browse repositories

搜索lombok,然后安装plugins,需要稍等片刻。笔者截图已经安装好。

2.2 添加jar包

在项目中添加lombok的jar包,笔者用的是maven,所以在pom文件中添加了如下的依赖。gradle使用见官网。

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

3. 使用

lombok主要通过注解起作用,详细的注解见Lombok features。

With Lombok:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
public class UserEntity implements Serializable {
    private long userId;
    private String userName;
    private String sex;
}

编译后:

import java.beans.ConstructorProperties;
import java.io.Serializable;

public class UserEntity implements Serializable {
    private long userId;
    private String userName;
    private String sex;

    public long getUserId() {
        return this.userId;
    }

    public String getUserName() {
        return this.userName;
    }

    public String getSex() {
        return this.sex;
    }

    public void setUserId(long userId) {
        this.userId = userId;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public boolean equals(Object o) {
        if(o == this) {
            return true;
        } else if(!(o instanceof UserEntity)) {
            return false;
        } else {
            UserEntity other = (UserEntity)o;
            if(!other.canEqual(this)) {
                return false;
            } else if(this.getUserId() != other.getUserId()) {
                return false;
            } else {
                Object this$userName = this.getUserName();
                Object other$userName = other.getUserName();
                if(this$userName == null) {
                    if(other$userName != null) {
                        return false;
                    }
                } else if(!this$userName.equals(other$userName)) {
                    return false;
                }

                Object this$sex = this.getSex();
                Object other$sex = other.getSex();
                if(this$sex == null) {
                    if(other$sex != null) {
                        return false;
                    }
                } else if(!this$sex.equals(other$sex)) {
                    return false;
                }

                return true;
            }
        }
    }

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

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        long $userId = this.getUserId();
        int result = result * 59 + (int)($userId >>> 32 ^ $userId);
        Object $userName = this.getUserName();
        result = result * 59 + ($userName == null?43:$userName.hashCode());
        Object $sex = this.getSex();
        result = result * 59 + ($sex == null?43:$sex.hashCode());
        return result;
    }

    public String toString() {
        return "UserEntity(userId=" + this.getUserId() + ", userName=" + this.getUserName() + ", sex=" + this.getSex() + ")";
    }

    @ConstructorProperties({"userId", "userName", "sex"})
    public UserEntity(long userId, String userName, String sex) {
        this.userId = userId;
        this.userName = userName;
        this.sex = sex;
    }
}

这边介绍笔者经常使用到的注解。

  • val,用在局部变量前面,相当于将变量声明为final
  • @Value

用在类上,是@Data的不可变形式,相当于为属性添加final声明,只提供getter方法,而不提供setter方法

  • @Data

提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法。通常情况下,我们使用这个注解就足够了。

  • @NoArgsConstructor无参构造器
  • @AllArgsConstructor全参构造器
  • @ToString

  生成toString方法,默认情况下,会输出类名、所有属性,属性会按照顺序输出,以逗号分割。

  • @EqualsAndHashCode

默认情况下,会使用所有非瞬态(non-transient)和非静态(non-static)字段来生成equals和hascode方法,也可以指定具体使用哪些属性。

  • @Getter / @Setter

上面已经说过,一般用@data就不用额外加这个注解了。可以作用在类上 和属性上,放在类上,会对所有的非静态(non-static)属性生成Getter/Set ter方法,放在属性上,会对该属性生成Getter/Setter方法。并可以指定Getter/Setter方法的访问级别。

  • @NonNull,给方法参数增加这个注解会自动在方法内对该参数进行是否为空的校验,如果为空,则抛出NPE(NullPointerException)。
  • @Cleanup 自动管理资源,用在局部变量之前,在当前变量范围内即将执行完毕退出之前会自动清理资源,自动生成try-finally这样的代码来关闭流。
  • @Log

根据不同的注解生成不同类型的log对象,但是实例名称都是log,有7种可选实现类:

1). @Log4j

private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);

2). @Log4j2

private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);

3). @Slf4j

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

4). @XSlf4j

private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

5). @CommonsLog

private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

6). @JBossLog

private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);

7). @Log

private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());

默认情况下,logger的名字将会是被@Log注解的那个类的名字。当然这也可以被个性化命名,通过topic参数,如 @XSlf4j(topic="reporting")

4. 原理

lombok 主要通过注解生效,自jdk5引入注解,由两种解析方式。 第一种是运行时解析, @Retention(RetentionPolicy.RUNTIME), 定义注解的保留策略,这样可以通过反射拿到该注解。 另一种是编译时解析,有两种机制。

  • Annotation Processing Tool,apt自JDK5产生,JDK7已标记为过期,不推荐使用,JDK8中已彻底删除,自JDK6开始,可以使用Pluggable Annotation Processing API来替换它,apt被替换主要有2点原因。api都在com.sun.mirror非标准包下,还有就是没有集成到javac中,需要额外运行。
  • Pluggable Annotation Processing API lombok使用这种方式实现,基于JSR 269,自JDK6加入,作为apt的替代方案,它解决了apt的两个问题,javac在执行的时候会调用实现了该API的程序,这样我们就可以对编译器做一些增强,这时javac执行的过程如下:

5. 总结

这篇文章主要讲解了lombok的入门与使用。介绍了一些常用的lombok注解,大大简化了我们的开发工作和代码的简洁性。当然,lombok不支持多种参数构造器的重载,工具毕竟是工具,我感觉并不会有非常完美适合每个人的工具。最后,我个人还是很推荐这款插件的,毕竟我很懒,?。


参考

  1. Lombok Docs
  2. Java奇淫巧技之Lombok

本文分享自微信公众号 - aoho求索(aohoBlog),作者:aoho

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-10-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 云原生架构下的 API 网关实践:Kong (三)

    在前面的文章介绍了 Kong 的相关实践,本文将会介绍 Kong 的利器:插件以及自定义插件。

    aoho求索
  • JVM 的 GC 优化经验谈

    本文转载自:https://www.rowkey.me/blog/2016/11/02/java-profile/

    aoho求索
  • NSQ深入与实践

    1. 介绍 最近在研究一些消息中间件,常用的MQ如RabbitMQ,ActiveMQ,Kafka等。NSQ是一个基于Go语言的分布式实时消息平台,它基于MIT开...

    aoho求索
  • PostgreSQL启动

    Postgresql启动流程模块划分。启动时首先会创建内存上下文TopMemoryContext作为内存的root,之后的内存都在这个下进行分配;然后设置一些L...

    yzsDBA
  • Android使用SurfaceView实现飘赞动画

    最近做直播项目,需要实现点赞动画,一提起动画就想到了使用View的属性动画,后来想了一下,那么多用户点赞,会导致屏幕上出现很多View,开销太大,一定会很卡,所...

    砸漏
  • 简单工厂模式和策略模式的区别与结合

        简单工厂模式和策略模式是大部分程序员,在学习设计模式时接触得最早,或在工作实践中也是用得相对比较多的两个设计模式。

    陈珙
  • 【OpenCV教程】core 模块 - Mat - 基本图像容器

    从真实世界中获取数字图像有很多方法,比如数码相机、扫描仪、CT或者磁共振成像。无论哪种方法,我们(人类)看到的是图像,而让数字设备来“看“的时候,都是在记录图像...

    小白学视觉
  • 【深度知识】RPC原理及以太坊RPC的实现

    Remote Procedure Calls 远程过程调用 (RPC) 是一种协议,就是从一台机器(客户端)上通过参数传递的方式调用另一台机器(服务器)上的一个...

    辉哥
  • 深入MongoDB4.2新特性:字段级加密

    作为使用过MySQL或者之前MongoDB数据库的同学,应该很容易理解,绝大部分的电商、银行、社交平台的数据库敏感字段都会考虑加密处理。例如:支付宝、微信、微博...

    MongoDB中文社区
  • 30行代码实现微信自动回复机器人

    前段时间写过一篇微信好友大揭秘,很多朋友对itchat非常感兴趣,今天下午又学到了itchat另一种有趣的玩法---微信自动回复机器人。

    PM小王

扫码关注云+社区

领取腾讯云代金券