文章目录
- 简介
- MAVEN 依赖
- 常用的注解
- 1. @Data 注解 :
- 2. @Setter 注解:
- 3.@Getter 注解:
- 4.@Log4j or @Slf4j 注解
- 5.@NoArgsConstructor注解:
- 6.@AllArgsConstructor注解:
- 7.@RequiredArgsConstructor注解:
- 8.@Builder注解:
- 9.@Cleanup注解:
- 10.@SneakyThrows 注解:
- 11.@Accessors
简介
Lombok是一款Java开发插件,使得Java开发者可以通过其定义的一些注解来消除业务工程中冗长和繁琐的代码,尤其对于简单的Java模型对象(POJO)。
在开发环境中使用Lombok插件后,Java开发人员可以节省出重复构建,诸如hashCode和equals这样的方法以及各种业务对象模型的accessor和ToString等方法的大量时间。对于这些方法,它能够在编译源代码期间自动帮我们生成这些方法,并没有如反射那样降低程序的性能。
MAVEN 依赖
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope><version>1.18.24</version>
</dependency>
常用的注解
1. @Data 注解 :
一般用在类上,提供类所有属性的 get 和 set 方法,此外还提供了equals、canEqual、hashCode、toString等方法;
相当于注解集合。效果等同于 @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor 效果同和这5个注解的效果
需要注意的是,这里不包括@NoArgsConstructor和@AllArgsConstructor
所以, 一般使用@Data时,要配合这两个注解一起使用
2. @Setter 注解:
一般用在属性上,为属性提供 set 方法, 用在再类上则表示当前类中所有属性都生成set方法;
3.@Getter 注解:
用在属性上,为属性提供 get 方法, 用在再类上表示当前类中所有属性都生成get方法;
4.@Log4j or @Slf4j 注解
用在类上,为类提供一个 属性名为log 的 log4j日志对象;
5.@NoArgsConstructor注解:
用在类上,为类提供一个无参的构造方法;
6.@AllArgsConstructor注解:
用在类上,为类提供一个全参的构造方法;
- 通过 @AllArgsConstructor(access = AccessLevel.PROTECTED) , 可以指定构造器的访问权限
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class Demo{private String name;private int age;
}
编译后生成:
public class Demo {private String name;private int age;protected Demo(String name, int age) {this.name = name;this.age = age;}
}
- @AllArgsConstructor(access = AccessLevel.PROTECTED, staticName = “test”)
@AllArgsConstructor(access = AccessLevel.PROTECTED, staticName = "test")
public class Demo{private final int finalVal = 10;private String name;private int age;
}
编译后 :
public class Demo {private String name;private int age;private Demo(String name, int age) {this.name = name;this.age = age;}protected static Demo test(String name, int age) {return new Demo(name, age);}
}
上面效果为:可以指定生成的构造器的访问权限。但是如果指定了一个静态方法,那么构造器会自动会被private,只通过静态方法对外提供访问,并且我们发现final的属性值,是不会放进构造函数里面的
7.@RequiredArgsConstructor注解:
用在类上,生成一个包含 “特定参数” 的构造器,特定参数指的是那些有加上 final 修饰词的变量们;
@RequiredArgsConstructor注解则会将类中所有带有@NonNull注解 / org.jetbrains.annotations.NotNull注解的或者带有final修饰的成员变量生成对应的构造方法
测试案例:
@RequiredArgsConstructor
public class Demo {@NonNullprivate final int finalVal;@NonNullprivate String name;@NonNullprivate int age;
}
编译后生成:
import lombok.NonNull;public class Demo {@NonNullprivate final int finalVal;@NonNullprivate String name;@NonNullprivate int age;public Demo(@NonNull int finalVal, @NonNull String name, @NonNull int age) {if (name == null) {throw new NullPointerException("name is marked non-null but is null");} else {this.finalVal = finalVal;this.name = name;this.age = age;}}
}
8.@Builder注解:
用在类上,自动生成流式 set 值写法,从此之后再也不用写一堆 setter 了;
注意,虽然只要加上 @Builder 注解,我们就能够用流式写法快速设定对象的值,但是 setter 还是必须要写不能省略的,因为 Spring 或是其他框架有很多地方都会用到对象的 getter/setter 对他们取值/赋值所以通常是 @Data 和 @Builder 会一起用在同个类上,既方便我们流式写代码,也方便框架做事;
9.@Cleanup注解:
可以用在 IO 流上,用于关闭并释放资源;
例如下面例子,每次IO流操作后要在finally中关闭流,释放资源:
public class CleanupExample {public static void main(String[] args) throws IOException {InputStream in = new FileInputStream(args[0]);try {OutputStream out = new FileOutputStream(args[1]);try {byte[] b = new byte[10000];while (true) {int r = in.read(b);if (r == -1) break;out.write(b, 0, r);}} finally {if (out != null) {out.close();}}} finally {if (in != null) {in.close();}}}
}
类似以上的一个IO流操作的方法使用lombok 的 @Cleanup 注解后可以简化成这样:
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);}}
}
10.@SneakyThrows 注解:
利用了这一机制,将当前方法抛出的异常,包装成RuntimeException,骗过编译器,使得调用点可以不用显示处理异常信息,使用注解后不需要担心Exception的处理。例如:
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);}}
}
11.@Accessors
@Accessors 一个为getter和setter方法设计的更流畅的注解
这个注解要搭配@Getter与@Setter使用,用来修改默认的setter与getter方法的形式。
@Accessors属性详解
fluent 属性 : 链式的形式 这个特别好用,方法连缀越来越方便了
chain 属性 : 流式的形式(若无显示指定chain的值,也会把chain设置为true)
prefix 属性 : 生成指定前缀的属性的getter与setter方法,并且生成的getter与setter方法时会去除前缀
测试不使用@Accessors时
fluent属性
默认为false,当该值为 true 时,对应字段的 getter 方法前面就没有 get,setter 方法就不会有 set。
编译后生成:
public class Demo {private final int finalVal = 10;private String xxName;private int yyAge;public Demo() {}public int finalVal() {Objects.requireNonNull(this);return 10;}public String xxName() {return this.xxName;}public int yyAge() {return this.yyAge;}public Demo xxName(String xxName) {this.xxName = xxName;return this;}public Demo yyAge(int yyAge) {this.yyAge = yyAge;return this;}public String toString() {int var10000 = this.finalVal();return "Demo(finalVal=" + var10000 + ", xxName=" + this.xxName() + ", yyAge=" + this.yyAge() + ")";}
}
使用:
public class Main {public static void main(String[] args) {Demo demo = new Demo();// setter方法; 这里包含了chain=true的功能,可以链式设置值demo.xxName("lucky").yyAge(20);// getter方法System.out.println(demo.xxName() + "," + demo.yyAge());System.out.println("demo = " + demo);}
}
chain属性
不写默认为false,当该值为 true 时,对应字段的 setter 方法调用后,会返回当前对象, 进行链式设置值
编译后生成:
public class Demo {private final int finalVal = 10;private String xxName;private int yyAge;public Demo() {}public int getFinalVal() {Objects.requireNonNull(this);return 10;}public String getXxName() {return this.xxName;}public int getYyAge() {return this.yyAge;}public Demo setXxName(String xxName) {this.xxName = xxName;return this;}public Demo setYyAge(int yyAge) {this.yyAge = yyAge;return this;}public String toString() {int var10000 = this.getFinalVal();return "Demo(finalVal=" + var10000 + ", xxName=" + this.getXxName() + ", yyAge=" + this.getYyAge() + ")";}
}
使用
public class Main {public static void main(String[] args) {Demo demo = new Demo();// setter方法demo.setXxName("lucky").setYyAge(20);System.out.println("demo = " + demo);}
}
prefix属性
该属性是一个字符串数组,当该数组有值时,表示忽略字段中对应的前缀,生成对应的 getter 和 setter 方法。
如果,我们把它的前缀加到 @Accessors 的属性值中,则可以像没有前缀那样,去调用字段的 getter和 setter 方法。
这里只是把原有属性的前缀给去掉