——springboot依赖lombok插件、lombok常用注解

1 lombok插件

1.1 lombok插件简介

官方介绍如下:

意思是:lombok是一个能自动插入到编辑器和构建工具的java库。目的是为了简化java代码,开发者不需要写setter、getter和构造方法等,只需要几个或多个lombok注解就能实现。

Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。例如开发中经常需要写的pojo,都需要花时间去添加相应的getter、setter、构造器和equals等方法,当属性多时会出现大量的getter/setter方法,维护起来很麻烦,也容易出错。

1.2 springboot依赖lombok插件

springboot中只需要依赖lombok的jar包就可使用Lombok。

(1)方法一:可以在官网(Download)下载jar包:

(2)方法二: 可以使用maven添加依赖:

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

2 lombok常用注解

2.1 @NotNull

@NotNull注解如果设置在一个属性上,lombok将在自动生成的方法/构造函数体的开头插入一个空检查,抛出NullPointerException,并将参数的名称作为message。

lombok注解实现:

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.NonNull;@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample<T> {private int x, y;@NonNull private T description;@NoArgsConstructorpublic static class NoArgsExample {@NonNull private String field;}
}

等价代码:

public class ConstructorExample<T> {private int x, y;@NonNull private T description;private ConstructorExample(T description) {//空检查if (description == null) throw new NullPointerException("description");this.description = description;}public static <T> ConstructorExample<T> of(T description) {return new ConstructorExample<T>(description);}@java.beans.ConstructorProperties({"x", "y", "description"})protected ConstructorExample(int x, int y, T description) {//空检查if (description == null) throw new NullPointerException("description");this.x = x;this.y = y;this.description = description;}public static class NoArgsExample {@NonNull private String field;public NoArgsExample() {}}
}

2.2 @NoArgsConstructor、@RequiredArgsConstructor和@AllArgsConstructor

2.2.1 @NoArgsConstructor

生成不带参数的构造方法,即:无参构造方法。@NoArgsConstructor等价于:

public MessageInfo() {
}

如果存在被final修饰的属性,那么会编译失败。

可以设置force属性值为true,来避免编译错误。但是所有final修饰的属性会被初始化为final字段初始化为:0 或null 或 false。也就是说包装类型会被初始化为null,简单类型初始化为0或false。

2.2.2 @RequiredArgsConstructor

只为final / @non-null修饰字段(不包括static修饰的)生成带参数的构造方法。

2.2.3 @AllArgsConstructor

描述:为所有字段(包括final修饰的,不包括static修饰的)生成带参数的构造方法,即:全参数构造方法。

2.3 @Getter和@Setter

lombok官方文档的描述:

lombok注解实现:

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;public class GetterSetterExample {/*** Age of the person. Water is wet.* * @param age New value for this person's age. Sky is blue.* @return The current value of this person's age. Circles are round.*/@Getter @Setter private int age = 10;/*** Name of the person.* -- SETTER --* Changes the name of this person.* * @param name The new value.*/@Setter(AccessLevel.PROTECTED) private String name;@Override public String toString() {return String.format("%s (age: %d)", name, age);}
}

等价代码:

public class GetterSetterExample {/*** Age of the person. Water is wet.*/private int age = 10;/*** Name of the person.*/private String name;@Override public String toString() {return String.format("%s (age: %d)", name, age);}/*** Age of the person. Water is wet.** @return The current value of this person's age. Circles are round.*/public int getAge() {return age;}/*** Age of the person. Water is wet.** @param age New value for this person's age. Sky is blue.*/public void setAge(int age) {this.age = age;}/*** Changes the name of this person.** @param name The new value.*/protected void setName(String name) {this.name = name;}
}

2.3.1 @Getter

@Getter为非静态属性(non-static属性)生成getter方法;如果@Getter放在类上,则会为该类中所有非静态属性(non-static属性)生成getter方法。

2.3.2 @Setter

@Setter为非静态(non-static属性)和非final修饰的属性生成setter方法;如果@Setter放在类上,则会为该类中所有非静态(non-static属性)和非final修饰的属性生成setter方法。

2.4 @ToString、@ToString.Exclude、@ToString.Include

2.4.1 @ToString

为所有对象生成toString方法,该方法会打印对象的所有属性值。默认情况下,它将打印类名,以及按顺序打印每个字段(static静态属性除外),字段直接用逗号分隔。示例如下:

MessageInfo(msgId=1, content=null, count=null, enabled=null, remark=备注)

参数:

  1. includeFieldNames:boolean类型,指定是否打印所有属性,默认为true。
  2. callSuper:boolean类型,指定是否需要打印父类的属性,默认为false。

2.4.2 @ToString.Exclude

指定不打印的属性列表(static静态属性除外)。需要搭配@ToString使用。

2.4.3 @ToString.Include

指定要打印的属性列表(可以放在static静态属性上)。需要搭配@ToString使用。

Lombok实现:

import lombok.ToString;@ToString
public class ToStringExample {private static final int STATIC_VAR = 10;private String name;private Shape shape = new Square(5, 10);private String[] tags;@ToString.Exclude private int id;public String getName() {return this.name;}@ToString(callSuper=true, includeFieldNames=true)public static class Square extends Shape {private final int width, height;public Square(int width, int height) {this.width = width;this.height = height;}}
}

等价代码:

import java.util.Arrays;public class ToStringExample {private static final int STATIC_VAR = 10;private String name;private Shape shape = new Square(5, 10);private String[] tags;private int id;public String getName() {return this.name;}public static class Square extends Shape {private final int width, height;public Square(int width, int height) {this.width = width;this.height = height;}@Override public String toString() {return "Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";}}@Override public String toString() {return "ToStringExample(" + this.getName() + ", " + this.shape + ", " + Arrays.deepToString(this.tags) + ")";}
}

2.5 @SneakyThrows

(1)@SneakyThrows注解原理:

在java的异常体系中Exception异常有两种类型:
        1)编译时异常:普通Exception类,如:UnsupportedEncodingException、IOException

等。
        2)运行时异常:RuntimeException类,如:NullPointerException 空指针异常、

IndexOutOfBoundsException 数组越界异常等。
        第一种会强制要求抛出它的方法声明throws,调用者必须显式地去处理(try..catch)这个异常。设计的目的是为了提醒开发者处理一些场景中必然可能存在的异常情况。比如网络异常造成IOException。所有的运行时异常不需要捕获,编译时异常是一定要捕获,否则编译会报错。

但是编写代码时,大部分情况下的异常,我们都是一路往外抛了事。所以渐渐的java程序员处理Exception的常见手段就是外面包一层RuntimeException,接着往上丢。这种解决思想尤其在Spring中到处出现。@SneakyThrows就是利用了这一机制,将当前方法抛出的异常,包装成RuntimeException,骗过编译器,使得调用点可以不用显示处理异常信息。

处理异常的一般方式如下:

try{//do work}catch(Exception e){throw new RuntimeException(e);}

通过try...catch来捕获异常,并把异常封装成运行时异常后继续往上层抛去。代码中try...catch越多,代码就越臃肿。Lombok的@SneakyThrows注解就是为了消除这样的模板代码。

lombok注解实现:

import lombok.SneakyThrows;public class SneakyThrowsExample implements Runnable {@SneakyThrows(UnsupportedEncodingException.class)public String utf8ToString(byte[] bytes) {return new String(bytes, "UTF-8");}@SneakyThrowspublic void run() {throw new Throwable();}
}

等价代码:

import lombok.Lombok;
public class SneakyThrowsExample implements Runnable {public String utf8ToString(byte[] bytes) {try {return new String(bytes, "UTF-8");} catch (UnsupportedEncodingException e) {throw Lombok.sneakyThrow(e);}}public void run() {try {throw new Throwable();} catch (Throwable t) {throw Lombok.sneakyThrow(t);}}
}

显然将异常封装为运行时异常RuntimeException的关键藏在Lombok.sneakyThrow(t);中。可能大家都会以为这个方法就是new RuntimeException()之类的。然而事实并非如此。阅读代码可以看出整个方法其实最核心的逻辑是throw (T)t;,利用泛型将我们传入的Throwable强转为RuntimeException。

public static RuntimeException sneakyThrow(Throwable t) {if (t == null) throw new NullPointerException("t");return Lombok.<RuntimeException>sneakyThrow0(t);}
}private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {throw (T)t;}

那么问题来了,为什么这个地方可以对原来的异常进行强转为RuntimeExcption?以下为直接强转的代码,显然运行之后报类型转换异常。

private void sneakyThrowsTest() { try {throw new Exception();} catch (Throwable e) { // 直接将e强转为RuntimeException,运行到这里会报类型转换异常。throw (RuntimeException)e;}
}

实际上,这种做法是一种通过泛型欺骗了编译器,让编译器在编译期不报错,而最后在JVM虚拟机中执行的字节码的并没有区别编译时异常和运行时异常,只有是不是和抛不抛异常而已。

(2)@SneakyThrows和@SneakyThrows(UnsupportedEncodingException.class)的区别:

1)@SneakyThrows默认情况下会自动捕获Throwable类及其子类异常(也就是所有异常),然后封装成RuntimeException后抛出;

2)@SneakyThrows(UnsupportedEncodingException.class) 或 @SneakyThrows(value = {IOException.class, UnsupportedEncodingException.class}):表示指定捕获某几种异常(包括子类异常)然后封装成RuntimeException后抛出,其他异常不处理。

2.6 @Synchronized

作用同synchronized关键字,为防止并发访问实例对象方法或类静态方法。该注解需放在方法上。

@Synchronized是synchronized方法修饰符的一个更安全的变体。与synchronized一样,注释只能用于静态方法和非静态方法。它的操作类似于synchronized关键字,但是又略有不同。不同点:修饰静态方法时,@Synchronized的锁是对象锁($LOCK);Synchronize关键字的锁是类锁。修饰非静态方法时,@Synchronized的锁是对象锁($lock);Synchronize关键字的锁是对象锁(this)。关键字锁定了这个字段,但是注释锁定了一个名为$lock的字段,该字段是私有的。注意,@Synchronized的锁是一个私有的(private)

当然,我们可以在代码中手动创建$LOCK或$lock锁对象,如果我们定义了锁对象,那么lombok就不会自动创建$LOCK或$lock锁对象。

我们也可以通过@Synchronized("锁对象名")方式来指定锁对象的名称。但是千万要注意,如果我们指定锁对象的名称,那么我们必须要手动定义该锁对象,lombok不会为我们创建该锁对象!

Lombok注解实现:

import lombok.Synchronized;public class SynchronizedExample {//自定义的锁对象private final Object readLock = new Object();@Synchronizedpublic static void hello() {System.out.println("world");}@Synchronizedpublic int answerToLife() {return 42;}@Synchronized("readLock")public void foo() {System.out.println("bar");}
}

等价代码:

public class SynchronizedExample {//lombok自动生成的锁对象$LOCKprivate static final Object $LOCK = new Object[0];//lombok自动生成的锁对象$lockprivate 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");}}
}

2.7 @EqualsAndHashCode

根据对象的所有属性,生成equals和hashCode方法。

2.8 @Builder

@Builder注解可以为你的类生成复杂的构建器apis,自动生成所需的代码,使类可以用下面类似的代码实例化,例如:

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

如果@Builder放在类上了,那么就会自动生成一个私有全参构造函数,并将所有字段作为参数(就好像类上加@AllArgsConstructor(access = AccessLevel.PRIVATE))。一般情况下@Builder搭配@Getter使用。

一个带有@Builder注解的方法会生成以下7个东西:

  • An inner static class named FooBuilder, with the same type arguments as the static method (called the builder).
  • In the builder: One private non-static non-final field for each parameter of the target.
  • In the builder: A package private no-args empty constructor.
  • In the builder: A 'setter'-like method for each parameter of the target: It has the same type as that parameter and the same name. It returns the builder itself, so that the setter calls can be chained, as in the above example.
  • In the builder: A build() method which calls the method, passing in each field. It returns the same type that the target returns.
  • In the builder: A sensible toString() implementation.
  • In the class containing the target: A builder() method, which creates a new instance of the builder.

lombok注解实现:

@Builderclass Example<T> {private T foo;private final String bar;}

等价代码:

class Example<T> {private T foo;private final String bar;private Example(T foo, String bar) {this.foo = foo;this.bar = bar;}public static <T> ExampleBuilder<T> builder() {return new ExampleBuilder<T>();}public static class ExampleBuilder<T> {private T foo;private String bar;private ExampleBuilder() {}public ExampleBuilder foo(T foo) {this.foo = foo;return this;}public ExampleBuilder bar(String bar) {this.bar = bar;return this;}@java.lang.Override public String toString() {return "ExampleBuilder(foo = " + foo + ", bar = " + bar + ")";}public Example build() {return new Example(foo, bar);}}}

2.9 @Data和@Value

2.9.1 @Data

@Data注解等价于:@Getter + @Setter + @RequiredArgsConstructor + @ToString  + @EqualsAndHashCode。

@Data为所有字段生成getter、构造函数、toString、hashCode和equals方法,检查所有@NotNull约束字段。也会为所有非final字段生成setter方法。具体详见等价的注解。

2.9.2 @Value

@Value注解等价于: @Getter+ @AllArgsConstructor + @ToString + @EqualsAndHashCode + @FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE)

@Value是@Data的不可变变量。默认情况下,所有属性字段都被设置为private和final,类本身也被设置为final,并且不会为属性生成setter方法。像@Data一样,还生成了有用的toString()、equals()和hashCode()方法,并为每个字段生成getter方法,还生成了覆盖每个参数的构造函数(除了在字段声明中初始化的final字段)。

lombok注解实现:

import lombok.AccessLevel;
import lombok.experimental.NonFinal;
import lombok.experimental.Value;
import lombok.experimental.With;
import lombok.ToString;@Value public class ValueExample {String name;@With(AccessLevel.PACKAGE) @NonFinal int age;double score;protected String[] tags;@ToString(includeFieldNames=true)@Value(staticConstructor="of")public static class Exercise<T> {String name;T value;}
}

等价代码:

import java.util.Arrays;public final class ValueExample {private final String name;private int age;private final double score;protected final String[] tags;@java.beans.ConstructorProperties({"name", "age", "score", "tags"})public ValueExample(String name, int age, double score, String[] tags) {this.name = name;this.age = age;this.score = score;this.tags = tags;}public String getName() {return this.name;}public int getAge() {return this.age;}public double getScore() {return this.score;}public String[] getTags() {return this.tags;}@java.lang.Overridepublic boolean equals(Object o) {if (o == this) return true;if (!(o instanceof ValueExample)) return false;final ValueExample other = (ValueExample)o;final Object this$name = this.getName();final Object other$name = other.getName();if (this$name == null ? other$name != null : !this$name.equals(other$name)) 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;}@java.lang.Overridepublic int hashCode() {final int PRIME = 59;int result = 1;final Object $name = this.getName();result = result * PRIME + ($name == null ? 43 : $name.hashCode());result = result * PRIME + this.getAge();final long $score = Double.doubleToLongBits(this.getScore());result = result * PRIME + (int)($score >>> 32 ^ $score);result = result * PRIME + Arrays.deepHashCode(this.getTags());return result;}@java.lang.Overridepublic String toString() {return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")";}ValueExample withAge(int age) {return this.age == age ? this : new ValueExample(name, age, score, tags);}public static final class Exercise<T> {private final String name;private final T value;private Exercise(String name, T value) {this.name = name;this.value = value;}public static <T> Exercise<T> of(String name, T value) {return new Exercise<T>(name, value);}public String getName() {return this.name;}public T getValue() {return this.value;}@java.lang.Overridepublic boolean equals(Object o) {if (o == this) return true;if (!(o instanceof ValueExample.Exercise)) return false;final Exercise<?> other = (Exercise<?>)o;final Object this$name = this.getName();final Object other$name = other.getName();if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;final Object this$value = this.getValue();final Object other$value = other.getValue();if (this$value == null ? other$value != null : !this$value.equals(other$value)) return false;return true;}@java.lang.Overridepublic int hashCode() {final int PRIME = 59;int result = 1;final Object $name = this.getName();result = result * PRIME + ($name == null ? 43 : $name.hashCode());final Object $value = this.getValue();result = result * PRIME + ($value == null ? 43 : $value.hashCode());return result;}@java.lang.Overridepublic String toString() {return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")";}}
}

至此,根据官方文档,详细通过示例介绍了lombok轻量级插件的使用。

springboot依赖lombok插件、lombok常用注解相关推荐

  1. TkMyBatis插件构造方法常用注解

    一.使用TkMyBatis插件 1.步骤: 1.在 SpringBoot启动类上面添加扫描Mapper接口注解 @MapperSan("Mapper层接口权限定名").并使用:tk ...

  2. SpringBoot Cloud必须掌握的常用注解

    使用注解的优势: 1.采用纯java代码,不在需要配置繁杂的xml文件2.在配置中也可享受面向对象带来的好处3.类型安全对重构可以提供良好的支持4.减少复杂配置文件的同时亦能享受到springIoC容 ...

  3. springboot 集成 Swagger2 配置以及常用注解的说明和使用 ( 超详细)

    一.注解的使用 和 说明 结构化说明如下: @Api:用在请求的类上,表示对类的说明      tags="说明该类的作用,可以在UI界面上看到的注解"    (也就是给类取别名) ...

  4. SpringBoot | 第六章:常用注解介绍及简单使用

    前言 之前几个章节,大部分都是算介绍springboot的一些外围配置,比如日志 配置等.这章节开始,开始总结一些关于springboot的综合开发的知识点.由于SpringBoot本身是基于Spri ...

  5. SpringBoot指南(二)——常用注解及操作

    文章目录 1 Spring 1.1 @SpringBootApplication 1.2 @Configuration 1.3 @Component.@Controller.@Service.@Rep ...

  6. idea 使用 lombok插件

    文章目录 前言 一.Lombok是什么? 二.如何使用Lombok 三.lombok中的常用注解 四.使用中遇到的问题 总结 前言 最近在使用idea,突然发现java实体类可以像Visual Stu ...

  7. lombok插件介绍

    lombok插件 Lombok项目是一个java库,它可以自动插入到编辑器和构建工具中,增强java的性能.不要再写另一个getter或equals方法,只要有一个注释,你的类就有一个功能齐全的构建器 ...

  8. Java常用注解以及使用场景示例

    Java注解定义 Java注解是Java编程语言中的一种特殊形式的元数据,它们可以用于为程序的各个元素(例如类.方法.字段等)添加额外的信息和属性.注解是在Java 5中引入的,通过在代码中使用注解, ...

  9. 【Mybatisplus】创建Spring Boot工程实现用户自定义功能Service接口和常用注解总结

    目录 1.测试自定义功能 2.通用Service 创建Service接口和实现类 测试查询数据库中有多少条记录 测试批量添加操作(通过单个批量增加循环实现) 3.常用注解(@TableName) 解决 ...

最新文章

  1. 数据科学工具 Jupyter Notebook 教程(一)
  2. DeepMind推出首个商业产品,30秒内准确诊断眼疾!
  3. [JZOJ5281]钦点题解--瞎搞+链表
  4. 给linux下网站目录配置SFTP
  5. Ubuntu10.04各文件夹的作用
  6. Android Google Map –两点之间的绘图路线
  7. ANDROID AIDL 1
  8. IOS 获取.plist文件的数据
  9. lasso模型可以用spss_互助问答第65期: 静态面板模型可以用GMM估计吗?
  10. 计算机考试准考证怎么下载
  11. yarn install报网络问题
  12. day 05 DQL数据查询语言---连接查询---登堂入室
  13. tableau无法建立连接_外部服务连接疑难解答 - Tableau
  14. 重磅:银保监发布消金公司监管评级办法,评级为5级恐被退市(全文重点已标出)
  15. 基于echarts+js+fexible.js实现的数据可视化适配案例(附源代码)
  16. Podman 部署私有镜像仓库
  17. latex插入参考文献小技巧
  18. 浅显易懂了解JavaScript回调函数
  19. GBASE 8s DB-Access菜单选项说明
  20. nginx防止别人域名恶意解析到服务器 和 网页被frame的方法

热门文章

  1. SQL Server辅助插件——SQL Prompt
  2. 【JavaScript 逆向】AST 技术反混淆
  3. visualassist飞鸟的专栏
  4. 【GMS认证】MBA政策解读
  5. umi+@umijs/plugin-qiankun的应用
  6. Ubuntu python3安装pandas【问题解决】
  7. 拓嘉启远电商:如何搭建拼多多的私域流量池
  8. 银行RPA的5个案例场景展示
  9. 一级计算机字处理知识点,全国计算机等级考试一级word文字处理题考点
  10. ~5 ccf 2021-12-2 序列查询新解