刚从git拉取的工程,发现idea报错,找不到bean中的的get、set方法。是因为类中使用了lombok的注解@Data,idea本身是不理解这个注解的,会报错找不到set方法,所以需要在idea中安装插件lombok plugin。
Lombok 是一款 Java 开发插件,使得 Java 开发者可以通过其定义的一些注解来消除业务工程中冗长和繁琐的代码,尤其对于简单的 Java 模型对象(POJO)。在开发环境中使用 Lombok 插件后,Java 开发人员可以节省出重复构建,诸如 hashCode 和 equals 这样的方法以及各种业务对象模型的 accessor 和 toString 等方法的大量时间。对于这些方法,Lombok 能够在编译源代码期间自动帮我们生成这些方法,但并不会像反射那样降低程序的性能。
Lombok安装
IDEA中安装lombok插件
打开IDEA的Setting –> 选择Plugins选项 –> 选择MarketPlace –> 搜索lombok –> 点击安装 –> 安装完成重启IDEA –> 安装成功
引入依赖 pom.xml中加入
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
Lombok的scope=provided,说明它只在编译阶段生效,不需要打入包中。事实正是如此,Lombok在编译期将带Lombok注解的Java文件正确编译为完整的Class文件。
@Getter/@Setter
该注解使用在类或者属性上,为字段生成
Getter
和Setter
方法。
- 注解在类上会为类中的所有非静态成员变量生成
Getter
和Setter
方法- 非boolean类型和boolean类型:都生成
getXxxxx
和setXxxx
,可以用is+大写开头的Boolean类型- 如果类和字段上均使用相同的注解,字段上的注解会覆盖相同的注解,以字段上的注解为准
- 手工编写的Getter和Setter方法会抑制lombok中相同名称的Getter和Setter方法的生成。
- 可以通过
AccessLevel.NONE
禁用某个字段上的@Setter、@Getter
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class GetterSetterExample {
private int age = 10;
@Getter(AccessLevel.NONE)@Setter(AccessLevel.PROTECTED) private String name;
}
public class GetterSetterExample {
private int age = 10;
private String name;
//自动生成Getter、Setter
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//属性优先级高于类
protected void setName(String name) {
this.name = name;
}
}
@ToString
生成
toString()
方法,默认情况下,它会以逗号分隔,按顺序,打印类名称以及每个非静态成员变量。
- 如果需要可以通过注释参数
includeFieldNames
来控制输出中是否包含的属性名称。- 通过
@ToString.Exclude
注解某一字段,可以从生成的方法中排除特定字段。- 也可使用
@ToString(onlyExplicitlyIncluded = true)
标注类,然后使用@ToString.Include
标注想要输入的字段。- 通过
@ToString(callSuper = true)
参数继承父类的输出。
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=false)
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
}
}
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;
}
private static class Square extends Shape {
private final int width;
private final int height;
private Square(int width, int height) {
this.width = width;
this.height = height;
}
@Override
public java.lang.String toString() {
//继承父类,排除属性名
return "ToStringExample.Square(super=" + super.toString() + ", " + this.width + ", " + this.height + ")";
}
}
@Override
public java.lang.String toString() {
//exclude "id"
return "ToStringExample(name=" + this.getName() + ", shape=" + this.shape + ", tags=" + java.util.Arrays.deepToString(this.tags) + ")";
}
}
@EqualsAndHashCode
任何类使用@EqualsAndHashCode标注生成hashCode()和equals()方法,默认情况下,它将使用所有非静态,非transient字段。但可以通过在可选的@EqualsAndHashCode.Include 或者@EqualsAndHashCode.Exclude注解字段来排除或包含指定字段
类似于
@toString
@EqualsAndHashCode.Exclude
排除具体字段@EqualsAndHashCode.Include
包含指定字段,需和属性onlyExplicitlyIncluded = true
配合使用- 通过
callSuper = true
继承父类。
import lombok.EqualsAndHashCode;
@EqualsAndHashCode
public class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
@EqualsAndHashCode.Exclude private Shape shape = new Square(5, 10);
private String[] tags;
@EqualsAndHashCode.Exclude private int id;
public String getName() {
return this.name;
}
@EqualsAndHashCode(callSuper=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 EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.name;
}
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof EqualsAndHashCodeExample)) return false;
EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
if (!other.canEqual((Object)this)) return false;
if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
if (Double.compare(this.score, other.score) != 0) return false;
if (!Arrays.deepEquals(this.tags, other.tags)) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
final long temp1 = Double.doubleToLongBits(this.score);
result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode());
result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
result = (result*PRIME) + Arrays.deepHashCode(this.tags);
return result;
}
protected boolean canEqual(Object other) {
return other instanceof EqualsAndHashCodeExample;
}
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 boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Square)) return false;
Square other = (Square) o;
if (!other.canEqual((Object)this)) return false;
if (!super.equals(o)) return false;
if (this.width != other.width) return false;
if (this.height != other.height) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
result = (result*PRIME) + super.hashCode();
result = (result*PRIME) + this.width;
result = (result*PRIME) + this.height;
return result;
}
protected boolean canEqual(Object other) {
return other instanceof Square;
}
}
}
@Accessors
@Accessors 主要用于控制生成的getter和setter
- fluent
- chain
- prefix
@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
给类增加无参构造器、指定参数的构造器、包含所有参数的构造器
- @NoArgsConstructor:使用在类上,提供一个无参构造器。当类中有final字段没有被初始化时,编译器会报错,此时可用@NoArgsConstructor(force = true),然后就会为没有初始化的final字段设置默认值 0 / false / null, 这样编译器就不会报错。对于具有约束的字段(例如@NonNull字段),不会生成检查或分配,因此请注意,正确初始化这些字段之前,这些约束无效。
- @RequiredArgsConstructor:使用在类上,生成一个有参构造函数,其中每个参数对应为类中所有带有 @NonNull 注解的和以final修饰的未经初始化的字段。
- @RequiredArgsConstructor(staticName = “of”)会生成一个of()的静态工厂方法,并把构造方法设置为私有的。
- @AllArgsConstructor:使用在类上,该注解提供一个全参数的构造方法,默认不提供无参构造。 这里的全参不包括已初始化的final字段。
- 这三个注解都会忽略static变量。
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample<T> {
private int x, y;
private final String name;
@NonNull
private T description;
private static int count;
@NoArgsConstructor
public static class NoArgsExample {
@NonNull
private String field;
}
}
// Generated by delombok at Mon Feb 25 09:40:52 CST 2019
package com.zybank.lombokdemo.entity;
import lombok.*;
public class ConstructorExample<T> {
private int x;
private int y;
private final String name;
@NonNull
private T description;
private static int count;
public static class NoArgsExample {
@NonNull
private String field;
@java.lang.SuppressWarnings("all")
public NoArgsExample() {
}
}
private ConstructorExample(final String name, @NonNull final T description) {
if (description == null) {
throw new java.lang.NullPointerException("description is marked @NonNull but is null");
}
this.name = name;
this.description = description;
}
public static <T> ConstructorExample<T> of(final String name, @NonNull final T description) {
return new ConstructorExample<T>(name, description);
}
protected ConstructorExample(final int x, final int y, final String name, @NonNull final T description) {
if (description == null) {
throw new java.lang.NullPointerException("description is marked @NonNull but is null");
}
this.x = x;
this.y = y;
this.name = name;
this.description = description;
}
}
@Data
@Data
包含了@ToString
、@EqualsAndHashCode
、@Getter
/@Setter
和@RequiredArgsConstructor
的功能。
- 虽然
@Data
注解非常有用,但是它的控制粒度较粗(Class级别),而且@Data
不能设置callSuper、
includeFieldNames
和exclude
等,如果需要改变默认值,可以使用相应的注解,@Data
会自动遵循这些注解。@Data
提供了一个可以生成静态工厂的单一参数@Data(staticConstructor=”of”)
,会生成一个of()的静态工厂方法,并把构造方法设置为私有的。
package com.zybank.lombokdemo;
import lombok.*;
@ToString(includeFieldNames=false)
//生成静态工厂
@Data(staticConstructor = "of")
public class DataExample {
private final String name;
//自定义Setter方法
@Setter(AccessLevel.PACKAGE)
private int age;
private double score;
private String[] tags;
}
// Generated by delombok at Mon Feb 25 16:27:59 CST 2019
package com.zybank.lombokdemo;
import lombok.*;
public class DataExample {
private final String name;
private int age;
private double score;
private String[] tags;
@java.lang.Override
public java.lang.String toString() {
return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + java.util.Arrays.deepToString(this.getTags()) + ")";
}
private DataExample(final String name) {
this.name = name;
}
public static DataExample of(final String name) {
return new DataExample(name);
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
@java.lang.SuppressWarnings("all")
public double getScore() {
return this.score;
}
public String[] getTags() {
return this.tags;
}
public void setScore(final double score) {
this.score = score;
}
void setAge(final int age) {
this.age = age;
}
public void setTags(final String[] tags) {
this.tags = tags;
}
@java.lang.Override
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof DataExample)) return false;
final DataExample other = (DataExample) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$name = this.getName();
final java.lang.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 (java.lang.Double.compare(this.getScore(), other.getScore()) != 0) return false;
if (!java.util.Arrays.deepEquals(this.getTags(), other.getTags())) return false;
return true;
}
protected boolean canEqual(final java.lang.Object other) {
return other instanceof DataExample;
}
@java.lang.Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $name = this.getName();
result = result * PRIME + ($name == null ? 43 : $name.hashCode());
result = result * PRIME + this.getAge();
final long $score = java.lang.Double.doubleToLongBits(this.getScore());
result = result * PRIME + (int) ($score >>> 32 ^ $score);
result = result * PRIME + java.util.Arrays.deepHashCode(this.getTags());
return result;
}
}
@Value
该注解用于修饰类,是
@Data
的不可变形式,生成immutable Class。字段都被修饰为private
和final
,默认的情况下不会生成settter
,默认类本身也是final
的。
实际上@Value
等价于final
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@Getter
import lombok.AccessLevel;
import lombok.experimental.NonFinal;
import lombok.experimental.Wither;
import lombok.ToString;
import lombok.Value;
@Value public class ValueExample {
String name;
@Wither(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.Override
public 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.Override
public 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.Override
public 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.Override
public 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.Override
public 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.Override
public String toString() {
return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")";
}
}
}
@NonNull
使用
@NonNull
注解标注方法或构造函数的参数,让lombok
为您生成null-check
语句。配合
lomok
中其他生成完整方法和构造函数的注解(比如@Setter
注解),仅需将@NonNull
标注在成员变量上,就可在生成的方法和构造函数中加入null-check
。反之,就必须在入参中标注。
lombok
会探测开发者自己编写的null-check
语句,如果存在就不在生成。if
条件语句必须严格按照PARAMNAME == null
的形式书写。
import lombok.NonNull;
public class NonNullExample {
private String name;
public void setName(@NonNull String name) {
this.name = name;
}
}
public class NonNullExample {
private String name;
public void setName(String name) {
if (name == null) {
throw new NullPointerException("name is marked @NonNull but is null");
}
this.name = name;
}
}
@Builder : 注解在类上, 为类提供一个内部的 Builder
@Synchronized : 注解在方法上, 为方法提供同步锁
@Log4j : 注解在类上, 为类提供一个属性名为 log 的 log4j 的日志对象
@Slf4j : 注解在类上, 为类提供一个属性名为 log 的 log4j 的日志对象