减少代码开发工作的Java库lombok及注解的使用学习

目录
  • 前言
  • Lombok是什么
  • 安装
    • 对于eclipse
    • 对于 IDEA
  • QuickStart
    • @Setter/@Getter
    • @ToString
    • exclude 参数
    • doNotUseGetters 参数
    • includeFieldNames参数
    • callSuper 参数
    • @NonNull
    • @EqualsAndHashCode
      • 参数
    • @Data
    • @Cleanup
    • @NoArgsConstructor/@RequiredArgsConstructor/@AllArgsConstructor
    • @Value
    • @builder
    • @SneakyThrows
    • @Synchronized
    • @Getter(lazy=true)
    • @Log

前言

Laziness is a virtue!

每当写pojo类时,都会重复写一些setter/getter/toString方法等大量的模版代码,无聊繁琐却又不得不做,这会让这个类变得又臭又长,却没有多少实质的东西

Lombok是什么

Lombok是一个旨在减少代码开发工作的Java库。它提供了一些简单的注解,并以此来消除java中臃肿的模版代码,比如 pojo 中最常见的 setter/getter 方法, 比如 toString 方法, 比如 equals 方法等等,还可以帮助我们关闭流,即使 JDK7 中已经有了 TWR 特性,但这个包很值得一试。

通过几个简单的注解,将模版代码在编译时写入程序。使用 eclipse 可以在 Outline 窗口看到生成的方法,但是在源码里是干净的.

安装

首先去 lombok 官网下载jar 包。

只是把 jar 包下载下来并导入工程中,会发现 IDE 不识别它的注解,那怎么办?

对于eclipse

将 lombok.jar 复制到 eclipse.ini 所在的目录下,然后编辑 eclipse.ini 文件, 在它的末尾插入以下两行并保存:

Xbootclasspath/a:lombok.jar
javaagent:lombok.jar

接着重启 eclipse 就可以愉快地使用这个库了。

对于 IDEA

在 IntelliJ 的插件中心可以找到它。

QuickStart

Lombok 提供的注解不多,但都好用,简要说一下常用的几个。

@Setter/@Getter

这两个注解修饰成员变量,可用于生成 setter/gettter 模版代码。
举个栗子:

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
public class Student {
    @Setter @Getter private String name;
    @Getter(AccessLevel.PROTECTED) private int age;// 可以指定访问权限
    @Setter @Getter private String[] hobbies;
}

将字节码文件反编译后可以看到下面这段代码

public class Student {
  private String name;
  private int age;
  private String[] hobbies;
  public String getName() { return this.name; }
  public void setName(String name) { this.name = name; }
  protected int getAge() { return this.age; }
  public String[] getHobbies() { return this.hobbies; }
  public void setHobbies(String[] hobbies) { this.hobbies = hobbies; }
}

@ToString

import lombok.ToString;
@ToString(exclude="id")
public class ToStringExample {
    private int id;
    private String name;
    private String[] tags;
}

编译后

import java.util.Arrays;
public class ToStringExample {
  public String toString() {
    return "ToStringExample(name=" + this.name + ", tags=" + Arrays.deepToString(this.tags) + ")";
  }
  private int id;
  private String name;
  private String[] tags;
}

我们发现,对于数组,在写 toString 方法时使用了 Arrays类的 静态方法 deepToString

来看 eclipse 自动生成的 toString 方法:

@Override
public String toString() {
    return "ToStringExample [name=" + name + ", tags=" + Arrays.toString(tags) + "]";
}

eclipse 中对于数组采用的是 Arrays.toString()

区别:这两个方法的区别是这样的,对于多维数组,使用 toString 只能打印出内部数组的名字,这时需要使用 deepToString 方法,它能将内部数组的内容全部打印出来。

exclude 参数

可以指定哪些属性不出现在 toString 方法中, 比如 exclude={"id", "name"}

doNotUseGetters 参数

当类中有成员变量的 getter 方法时,生成 toString 方法会使用这些 getter 方法,比如

public String toString() {
    return "ToStringExample(name=" + getName() + ", tags=" + Arrays.deepToString(getTags()) + ")";
}

但是将该参数设置为 true 时(默认为 false),生成 toString 方法时就不会使用 getter 方法,而是直接使用这些成员变量,比如

public String toString() {
    return "ToStringExample(name=" + this.name + ", tags=" + Arrays.deepToString(this.tags) + ")";
}

includeFieldNames参数

原本是以 fieldName = fieldValue 的格式来生成 toString 方法的,但是将该参数设置为 false 后(默认是 true),就不会显示 fieldName 了,而只是生成 fieldValue, 比如

public String toString() {
  return "ToStringExample(" + getId() + ", " + getName() + ", " + Arrays.deepToString(getTags()) + ")";
}

callSuper 参数

若类 A 是类 B 的子类,那么在 A 类重写 toString 时,若把该参数设置为 true,会加入下面这段代码,即也会把父类 B 的 toString 也写入。

super=" + super.toString()

@NonNull

检查传入对象是否为 Null,若为null,则抛出NullPointerException异常。
举个栗子

import lombok.NonNull;
public class NonNullExample extends Student{
    private String name;
    public NonNullExample(@NonNull Student student) {
        this.name = student.getName();
    }
}

编译后代码

import lombok.NonNull;
public class NonNullExample extends Student {
    private String name;
    public NonNullExample(@NonNull Student student) {
        if (student == null)
            throw new NullPointerException("student");
        this.name = student.getName();
  }
}

@EqualsAndHashCode

用在类上,用于生成 equals 和 hashcode 方法。
举个栗子

@EqualsAndHashCode(exclude={"id"})
public class EqualsAndHashCodeExample {
     private transient int transientVar = 10;
     private String name;
     private double score;
     private String[] tags;
     private int id;
}

编译后代码

import java.util.Arrays;
public class EqualsAndHashCodeExample {
    public int hashCode() {
        int PRIME = 59;
        int result = 1;
        Object $name = this.name;
        result = result * 59 + ($name == null ? 43 : $name.hashCode());
        long $score = Double.doubleToLongBits(this.score);
        result = result * 59 + (int)($score ^ $score >>> 32);
        result = result * 59 + Arrays.deepHashCode(this.tags);
        return result;
    }
    protected boolean canEqual(Object other) {
        return other instanceof EqualsAndHashCodeExample;
    }
    public boolean equals(Object o) {
        if (o == this)  return true;
        if (!(o instanceof EqualsAndHashCodeExample)) return false;
        EqualsAndHashCodeExample other = (EqualsAndHashCodeExample)o;
        if (!other.canEqual(this)) return false;
        Object this$name = this.name;
        Object other$name = other.name;
        if (this$name == null ? other$name != null : !this$name.equals(other$name))
            return false;
        if (Double.compare(this.score, other.score) != 0)
            return false;
        return Arrays.deepEquals(this.tags, other.tags);
    }
private transient int transientVar = 10;
private String name;
private double score;
private String[] tags;
private int id;
}

可以看出transient修饰的变量,不会参与。

参数

参数 of 用来指定参与的变量,其他的跟 @ToString 注解类似。

@Data

该注解用于修饰类,会自动生成getter/setter方法, 以及重写equals()hashcode()toString()方法。

@Cleanup

该注解可以用来自动管理资源,用在局部变量之前,在当前变量范围内即将执行完毕退出之前会自动清理资源, 自动生成try­finally这样的代码来关闭流

举个栗子:

import lombok.Cleanup;
import java.io.*;
public class CleanupExample {
  public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
      @Cleanup OutputStream out = new FileOutputStream(args[1]);
        byte[] b = new byte[10000];
        while (true) {
        int r = in.read(b);
        if (r == -1) break;
        out.write(b, 0, r);
       }
     }
}

@NoArgsConstructor/@RequiredArgsConstructor/@AllArgsConstructor

这三个注解修饰在类上。

@NoArgsConstructor 用于生成一个无参构造方法。

@RequiredArgsConstructor 会生成一个包含了被@NotNull标识的变量的构造方法。同样可以设置生成构造方法的权限,使用 access参数进行设置。

@AllArgsConstructor 会生成一个包含所有变量, 同时如果变量使用了@NotNull,会进行是否为空的校验。

举个栗子:

import lombok.*;
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample {
    private int x;
    private int y;
    @NonNull private String desc;
    @NoArgsConstructor
    public class NoArgsExample{
        private String field;
    }
}

这与下面这段代码是等价的,

import java.beans.ConstructorProperties;
public class ConstructorExample {
    public static ConstructorExample of(@lombok.NonNull String desc) {
        return new ConstructorExample(desc);
    }
    private ConstructorExample(@lombok.NonNull String desc) {
        if (desc == null) throw new NullPointerException("desc");
        this.desc = desc;
    }
    @ConstructorProperties({"x", "y", "desc"})
    protected ConstructorExample(int x, int y, @lombok.NonNull String desc) {
        if (desc == null) throw new NullPointerException("desc");
        this.x = x;
        this.y = y;
        this.desc = desc;
    }
    private int x;
    private int y;
    @lombok.NonNull
    private String desc;
    public class NoArgsExample
    {
        private String field;
        public NoArgsExample() {}
    }
}

@Value

该注解用于修饰类,是@Data的不可变形式, 相当于为成员变量添加final声明, 只提供getter方法, 而不提供setter方法,然后还有 equals/hashCode/toString方法,以及一个包含所有参数的构造方法。

@builder

用在类、构造器、方法上,为你提供复杂的builder APIs,让你可以像如下方式调用

Person.builder().name("A
dam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build()

举个栗子:

import lombok.Builder;
import java.util.Set;
@Builder
public class BuilderExample {
    private String name;
    private int age;
}

反编译代码如下:

package tutorial.lombok;
    public class BuilderExample
    {
        public static class BuilderExampleBuilder
        {
            private String name;
            private int age;
            public BuilderExampleBuilder name(String name)
            {
                this.name = name;
                return this;
            }
            public BuilderExampleBuilder age(int age)
            {
                this.age = age;
                return this;
            }
            public BuilderExample build()
            {
                return new BuilderExample(name, age);
            }
            public String toString()
            {
                return (new StringBuilder()).append("BuilderExample.BuilderExampleBuilder(name=").append(name).append(", age=").append(age).append(")").toString();
            }
            BuilderExampleBuilder()
            {
            }
        }
        private String name;
        private int age;
        BuilderExample(String name, int age)
        {
            this.name = name;
            this.age = age;
        }
        public static BuilderExampleBuilder builder()
        {
            return new BuilderExampleBuilder();
        }
    }

注意:

使用@Singular注解的集合属性名必须使用s结尾, lombok会将属性名结尾的s去掉,剩余的名字会作为方法名, 向这个集合中添加元素。

@Builder 的参数builderClassName设置生成的builder方法名,buildMethodName 设置build方法名,builderMethodName设置builderMethod`方法名。
比如

@Builder(builderClassName = "GBuilder", buildMethodName = "buildG", builderMethodName = "GBuilder"

@SneakyThrows

自动抛受检异常, 而无需显式在方法上使用throws语句。

@Synchronized

用在方法上,将方法声明为同步的,并自动加锁,而锁对象是一个私有的属性 LOCK,而java中的synchronized关键字锁对象是this,锁在this或者自己的类对象上存在副作用,就是你不能阻止非受控代码去锁this或者类对象,这可能会导致竞争条件或者其它线程错误。

举个栗子:

import lombok. Synchronized;
public class SynchronizedExample {
    private final Object readLock = new Object() ;
    @Synchronized
    public static void hello() {
        System. out. println("world") ;
    }
    @Synchronized("readLock")
    public void foo() {
        System. out. println("bar") ;
    }
}

反编译代码如下:

public class SynchronizedExample {
    private static final Object $LOCK = new Object[0] ;
    private final Object readLock = new Object() ;
    public static void hello() {
        synchronized($LOCK) {
            System. out. println("world") ;
        }
    }
    public int answerToLife() {
        synchronized($lock) {
            return 42;
        }
    }
    public void foo() {
        synchronized(readLock) {
            System. out. println("bar") ;
        }
    }
}

@Getter(lazy=true)

可以替代经典的Double Check Lock样板代码。

举个栗子:

import lombok.Getter;
public class GetterLazyExample {
    @Getter(lazy=true) private final double[] cached = expensive();
    private double[] expensive() {
        double[] result = new double[1000000];
        for (int i = 0; i < result.length; i++) {
            result[i] = Math.asin(i);
        }
        return result;
    }
}

反编译代码如下,

import java.util.concurrent.atomic.AtomicReference;
public class GetterLazyExample
{
    private final AtomicReference cached = new AtomicReference();
    public GetterLazyExample()
    {
    }
    private double[] expensive()
    {
            double result[] = new double[0xf4240];
        for (int i = 0; i < result.length; i++)
            result[i] = Math.asin(i);
        return result;
    }
    public double[] getCached()
    {
        Object value = cached.get();
        if (value == null)
            synchronized (cached)
            {
                value = cached.get();
                if (value == null)
                {
                    double actualValue[] = expensive();
                    value = actualValue != null ? ((Object) (actualValue)) : ((Object) (cached));
                    cached.set(value);
                }
            }
        return (double[])(double[])(value != cached ? value : null);
    }
}

@Log

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

@CommonsLog
Creates log = org. apache. commons. logging. LogFactory. getLog(LogExample. class) ;
@Log
Creates log = java. util. logging. Logger. getLogger(LogExample. class. getName() ) ;
@Log4j
Creates log = org. apache. log4j. Logger. getLogger(LogExample. class) ;
@Log4j2
Creates log = org. apache. logging. log4j. LogManager. getLogger(LogExample. class) ;
@Slf4j
Creates log = org. slf4j. LoggerFactory. getLogger(LogExample. class) ;
@XSlf4j
Creates log = org. slf4j. ext. XLoggerFactory. getXLogger(LogExample. class) ;

举个栗子,

import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
@Log
public class LogExample {
    public static void main(String... args) {
        log.error("Something's wrong here");
    }
}
@Slf4j
public class LogExampleOther {
    public static void main(String... args) {
        log.error("Something else is wrong here");
    }
}
@CommonsLog(topic="CounterLog")
public class LogExampleCategory {
    public static void main(String... args) {
        log.error("Calling the 'CounterLog' with a message");
    }
}
@CommonsLog(topic="CounterLog")

这条语句会翻译成这样

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

以上就是减少代码开发工作的Java库lombok使用学习的详细内容,更多关于Java lombok库减少代码开发的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java 14 发布了,你还会使用Lombok?

    2020年3月17日发布,Java正式发布了JDK 14 ,目前已经可以开放下载.在JDK 14中,共有16个新特性,本文主要来介绍其中的一个特性:JEP 359: Records 官方吐槽最为致命 早在2019年2月份,Java 语言架构师 Brian Goetz,曾经写过一篇文章(http://cr.openjdk.java.net/~briangoetz/amber/datum.html ),详尽的说明了并吐槽了Java语言,他和很多程序员一样抱怨"Java太啰嗦"或有太多的&q

  • 利用json2POJO with Lombok 插件自动生成java类的操作

    前言 很多时候,我们定义接口或者调用别人的接口时,手里只有一份接口文档,文档中提供一段示例json格式的报文,我们需要根据json中的字段,挨个去定义java POJO 的字段属性. 属实费劲,且有时候万一手抖,个别字段填错了,就导致前后端联调不能一次性成功. 如果能有办法将json直接生成java POJO,岂不是能省去很多时间. 1.安装idea 插件 打开preferences → Plugins → marketplace → 输入:json2Pojo with Lombok,点击安装并

  • java项目中使用 Lombok遇到的问题小结

    一.Maven项目使用步骤一般包含两步,1)引入依赖 2)特定的 IDE 引入对应的插件 1)在POM中引入依赖 <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version

  • 关于Idea创建Java项目并引入lombok包的问题(lombok.jar包免费下载)

    一:场景 使用Idea工具创建java项目(非spring项目)时,已经安装了lombok插件却无法使用其中的注解 二: 原因 原因一: idea创建的项目默认是不支持注解的,需要手动勾选支持注解的选项 具体操作: File  >> setting >> 搜索Compiler >> 点击 Annotation processors >> 勾选 Enable processing >> 点击OK(下面有具体的图形操作流程) 原因二: idea安装后

  • Java中lombok的@Builder注解的解析与简单使用详解

    Lombok中@Builder用法 1.建造者模式简介:Builder 使用创建者模式又叫建造者模式.简单来说,就是一步步创建一个对象,它对用户屏蔽了里面构建的细节,但却可以精细地控制对象的构造过程. 2.注解类Builder.java注释: * The builder annotation creates a so-called 'builder' aspect to the class that is annotated or the class  * that contains a mem

  • 减少代码开发工作的Java库lombok及注解的使用学习

    目录 前言 Lombok是什么 安装 对于eclipse 对于 IDEA QuickStart @Setter/@Getter @ToString exclude 参数 doNotUseGetters 参数 includeFieldNames参数 callSuper 参数 @NonNull @EqualsAndHashCode 参数 @Data @Cleanup @NoArgsConstructor/@RequiredArgsConstructor/@AllArgsConstructor @Va

  • Java中Lombok @Value注解导致的variable not been initialized问题

    目录 背景 解决 背景 想要修改一个POJO类,在其中增加一个字段,但是增加以后就开始报错: 该类已经存在一个构造函数,为了不破坏该类原来的使用方式,于是重新写了一个构造方法,之前的构造函数未改动. 该类被Lombok的@Value注解修饰 解决 报错信息显示,变量未被初始化.于是主要排查是否有被初始化. 在重写的构造方法中,我已经对该变量进行了初始化. 不明所以,开始找不同,这个类中,唯一不熟悉的就是@Value注解,于是查看注解中的注释: /** * Generates a lot of c

  • 推荐两款java开发实用工具 hutool 和 lombok

    一.hutool工具 摘抄一段hutool工具的简介: Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,是项目中"util"包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务. hutool-aop JDK动态代理封装,提供非IOC下的切面支持 hutool-bloomFilter 布隆过滤,提供一些Hash算法的布隆过滤 hutool-cache 简单缓存实现 hutool-core 核心,包括Bean操作.

  • JAVA代码开发规范

    一.开发工具规范: 1. 开发工具经项目负责人调试后统一确定. 2. 开发工具一经确定不允许集成任何非统一插件,若有需要,经项目负责人同意后统一为 项目组成员添加. 3. 开发工具的编码格式不允许修改. 二.排版规范: 1. 关键词(或变量)和操作符之间加一个空格. 例如:int iCont = 1;//操作符和值之间有一个空格. 2. 相对独立的代码块与块之间加空行. 例如:两个方法之间需要用空格隔开. 3. 较长的语句.表达式等要分成多行书写. 4. 长表达式要在低优先级操作符处划分新行,操

  • Java使用lombok消除冗余代码的方法步骤

    一.项目背景 在写Java程序的时候经常会遇到如下情形: 新建了一个Class类,然后在其中设置了几个字段,最后还需要花费很多时间来建立getter和setter方法. lombok项目的产生就是为了省去我们手动创建getter和setter方法的麻烦,它能够在我们编译源码的时候自动帮我们生成getter和setter方法.即它最终能够达到的效果是:在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法. 比如源码文件: import java.

  • java开发工作中对InheritableThreadLocal使用思考

    目录 引言 1. 先说结论 2. 实验例子 3. 详解 3.1 JavaDoc 3.2 源码 3.2.1 childValue方法 4. 实验例子流程图 引言 最近在工作中结合线程池使用 InheritableThreadLocal 出现了获取线程变量“错误”的问题,看了相关的文档和源码后在此记录. 1. 先说结论 InheritableThreadLocal 只有在父线程创建子线程时,在子线程中才能获取到父线程中的线程变量: 当配合线程池使用时:“第一次在线程池中开启线程,能在子线程中获取到父

  • 5个可以加速开发的VueUse函数库(小结)

    目录 VueUse 有哪些实用程序? 将 VueUse 安装到你的 Vue 项目中 1.useRefHistory 跟踪响应式数据的更改 2.onClickOutside 关闭模态 3.useVModel 简化了 v-model 绑定 4.使用InterpObserver 跟踪元素可见性 5.useTransition 在值之间缓和 最后的想法 VueUse 是 Anthony Fu 的一个开源项目,它为 Vue 开发人员提供了大量适用于 Vue 2 和 Vue 3 的基本 Compositio

  • 使用Jitpack发布开源Java库的详细流程

    目录 gradle 发布流程 1.创建module 2.Gradle插件设置 3.项目上传github 4.github创建relase版本 5.发布开源库 6.使用 关于多模块moudle maven 关于多模块module 官方实例项目 很久之前也写过一篇使用Jitpack发布Android开源库的文章,详见Android发布项目到jitpack的完整步骤 近来因为工作原因,又重新整理总结一些使用Jitpack的相关使用技巧,由于现在Java常用的构建工具为Gradle和Maven,所以准备

  • IntelliJ IDEA安装插件阿里巴巴Java开发手册(Alibaba Java Coding Guidelines)

    以前看到过个:Java开发手册(阿里巴巴-公开版),这是个pdf文档,里面描述了一些Java开发的规约,里面确实有很多好用的规约,要是在学校就有机会看看的话,那么,在毕业之后,实际工作中就会少很多坑.现在,阿里巴巴又一次对这个文档进行了升级,直接变成了一个插件.你需要的就是:知道有这么个插件,然后,还得安装这个插件,那么以后,你在写代码的时候,这个插件就会自动的纠正你在写代码的时候的一些很low的不规范代码. 下面看怎么在这个 IntelliJ IDEA 上安装这个插件. 通过Jetbrains

  • java中lombok的@Data引发问题详解

    前言 我们问题lombok是可以精简我们的代码的,让开发人员把精力放在业务上,而它封装的注解我们在使用时,需要多注意一下:@Data注解它是一个混合注释,它包含了@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode的功能,而我们问题@EqualsAndHashCode是重写equals和hash的注释,如果你是一个类,那可以不关心它:而如果你的类中有继承(父类子类),那么就要注意一下了. 危险的@Data 子类

随机推荐