LomBok

最近,偶然看到东西——能够在开发的过程中用注解的方式,简化实体类。看起来还不错的样子,我挺喜欢,可以了解了解。说不定哪天就用上了。

于是我记下了学习笔记。上目录。

目录

什么是Lombok

根据百度百科的解释。

Lombok项目是一个java库,它可以自动插入到编辑器和构建工具中,增强java的性能。不需要再写getter、setter或equals方法,只要有一个注解,你的类就有一个功能齐全的构建器、自动记录变量等等。

也就是说,Lombok是为了简化JavaBean代码。

Lombok的作用——简化代码

Lombok的作用是简化代码。
按照我们通常的方法,角色的实体类代码如下:

 1 public class Role {
 2     private int rid;
 3     private String rname;
 4     private String level;
 5 
 6     public int getRid() {
 7         return rid;
 8     }
 9 
10     public void setRid(int rid) {
11         this.rid = rid;
12     }
13 
14     public String getRname() {
15         return rname;
16     }
17 
18     public void setRname(String rname) {
19         this.rname = rname;
20     }
21 
22     public String getLevel() {
23         return level;
24     }
25 
26     public void setLevel(String level) {
27         this.level = level;
28     }
29 
30     @Override
31     public String toString() {
32         return "Role{" +
33                 "rid=" + rid +
34                 ", rname='" + rname + '\'' +
35                 ", level='" + level + '\'' +
36                 '}';
37     }
38 }
Role

如果使用lombok,只需要如下代码:

1 @Data
2 public class Role {
3     private int rid;
4     private String rname;
5     private String level;
6 }
View Code

Lombok的优缺点

Lombok的优点

  • 代码简洁

Lombok的缺点

  • 强迫性。因为Lombok的使用要求开发者一定要在IDE中安装对应的插件。只要一个人安装了Lombok,其他人也需要安装,否则编译报错。
  • 可读性和调试性降低。在代码中使用了Lombok,确实可以帮忙减少很多代码,因为Lombok会帮忙自动生成很多代码。我们不能直接知道类中的getter方法被哪些类引用。
  • 不了解底层原理,容易出错。在使用Lombok过程中,如果对于各种注解的底层原理不理解的话,很容易产生意想不到的结果。

举一个简单的例子,我们知道,当我们使用@Data定义一个类的时候,会自动帮我们生成 equals() 方法 。但是如果只使用了 @Data ,而不使用 equalsAndHashCode(callSuper=true) 的话,会默认是 @EqualsAndHashCode(callSuper=false) ,这时候生成的 equals() 方法只会比较子类的属性,不会考虑从父类继承的属性,无论父类属性访问权限是否开放。

  • 影响升级。如果我们需要升级到某个新版本的JDK的时候,若其中的特性在Lombok中不支持的话就会受到影响。
  • 破坏抽象。如果我们在代码中直接使用Lombok,那么他会自动帮我们生成getter、setter 等方法,这就意味着,一个类中的所有参数都自动提供了设置和读取方法

对应Lombok缺点?

强迫性

对我来说,安装一个插件也不是很费事。当然,如果你要和人合作,他不愿意安装,那确实很难——相比起来,get、set、equals、toString等方法点几下鼠标和快捷键就生成了。所以,这个缺点主要是“势”。很多东西,用的人越多,维护他的人也越多,它的功能才能优化。

注:最新的IDEA似乎不需要安装插件,因为在IDEA中集成了。

可读性和调试性降低

我觉得可读性还是提高了,毕竟重复的代码减少了。其实通过IDEA可以很方便的找到某个属性的getter方法都被哪些类引用,这一点有待于进一步学习。

不了解底层原理,容易出错

每一个工具都有可能遇到坑,额,这个坑……很难理解吗?如果要开发越多人使用的东西,确实越需要谨慎——哪怕是看起来比较简单的新东西。所以,使用工具,确实要对它有所了解,否则容易出错。我们还是需要深度,更何况,Lombok没有特别深。

破坏抽象

这个要看使用场景。以我现在有限的代码来说,几乎所有参数都提供了get和set方法,并没有那么个性化的权限。如果真有个性化的权限,我希望使用注释的方式,这样更加一目了然。

很显然,类A聚集在一起的一行,或者两行代码,就能让我们知道属性的读取,或者写权限;类B,如果属性比较多,似乎相对看起来就没有那么方便了。需要个性化配置权限的时候,带有get和set的注解更一目了然。
Lombok中带有这样的注解:
@Setter/@Getter : 生成set和get方法。
影响升级

如果遇到这个问题,确实比较头疼,不知道发生它的概率。

不过,一般来说。以我有限的经验来说,同一个项目不会去随便升级JDK。难保一些插件和版本不对应。

个人看法

总之,lombok代码的思想还是很好的,它让代码的可读性提高了很多(写代码的时间倒是看不出节约,因为IDEA(或其他工具)都能快速生成get,set方法)。
对于他的缺点,大多数是因为固有的习惯,让很多人不适应;影响升级的问题,就像我们完成一件事情时,遇到的一些问题。如果更多的人接受这一思想,那么必定能够得到处理。
现实工作中,我们要人接受同一个工具、同一件事情不容易。可以提出自己的意见,但真正如果落实,要以实际的沟通为主。

Lombok原理

它的注解是在编译过程就生效的。其他的,我没关心……

不好意思,偶尔的不求甚解。

Lombok的使用准备(Idea)

使用准备包括两部,安装插件和添加项目依赖。

注:最新版的Ida似乎已经自带lombok插件(看来她是大势所趋)。

Lombok的安装

1. 使用快捷键【Crlt+Alt+S】(或点击菜单栏【File】—> 【Settings】)
2. 找到Lombox插件,并点击安装。等待安装完成。

安装完成后需要重启Idea。

添加项目依赖

打开pom.xml文件,加上项目依赖。

1 <dependency>
2     <groupId>org.projuectlombok</groupId>
3     <artifactId>lombok</artifactId>
4     <version>1.16.10</version>
5 </dependency>

正式使用Lombok

接下来,我们看看Lombox的常用注解有哪些。

写一个JavaBean

写一个简单的实体类。这也将是以后写实体类的常用注释。

1 @Data
2 public class User {
3     private  Integer id;
4     private  String username;
5     private String password;
6     private String phone;
7     private String email;
8 }
User

按【Alt + 7】,可以看到项目的结构如下。

可以知道,生成了一下类:

  • 类的构造方法
  • 所有属性的get和set方法
  •  equals(Object) 、 canEqul(Object) 和 hashCode() 的比较方法。
  •  toString() 输出打印方法。

我们能在项目的生成目录下查看对应JavaBean的生成文件。

常用注释——Getter和Setter

在字段中添加Getter注释

1 public class User {
2 
3     @Getter
4     private  Integer id;
5     private  String username;
6     private String password;
7     private String phone;
8     private String email;
9 }
User

此时,id字段默认生成Getter()方法,可以看到它的权限 public 。

 其实,Getter的属性可以设置生成权限的类型。

 1 public class UserGetter {
 2 
 3     @Getter(AccessLevel.PROTECTED)
 4     private  Integer id;
 5 
 6     private  String username;
 7     private String password;
 8     private String phone;
 9     private String email;
10 }
UserGetter

这时候生成的Getter方法将改变权限。

我们可以设置的权限包括:

AccessLevel属性
属性 权限
 AccessLevel. PUBLIC  public 
 AccessLevel. MODULE  
 AccessLevel. PROTECTED  protected
 AccessLevel. PACKAGE  
 AccessLevel. PRIVATE   private
 AccessLevel. NONE  无权限修饰符

在字段中添加Setter注释

同理,可以添加Setter注解。

1 public class UserSetter {
2 
3     @Setter
4     private  Integer id;
5     private  String username;
6     private String password;
7     private String phone;
8     private String email;
9 }
UserSetter

自动生成的Setter方法如下:

 同理,可以设置对应Setter方法的权限属性。

为类添加Getter和Setter注释

1 @Getter
2 public class UserClassGetSet {
3 
4     private  Integer id;
5     private  String username;
6     private String password;
7     private String phone;
8     private String email;
9 }
UserClassGetSet

该类的所有字段,将会生成get方法。

类似的,在类上添加 @Setter ,则会为所有的属性添加set方法。

注:static的成员,作为静态类型,不会生成get和set函数。
final成员,只生成getter()方法,不会生成set函数。

常用注释——toString()

通常,实体类中还会有默认打印数据的方法。我们一般为函数写 toString() 方法。

默认toString 注释

1 @ToString
2 public class UsertoString {
3 
4     private  Integer id;
5     private  String username;
6     private String password;
7     private String phone;
8     private String email;
9 }
UsertoString

可以看到,自动生成的toStirng方法为:

1 public String toString() {
2     return "UsertoString(id=" + this.id + ", username=" + this.username + ", password=" + this.password + ", phone=" + this.phone + ", email=" + this.email + ")";
3 }

默认会打印所有成员变量的值。

排除某个成员变量——属性exclude

有些时候,某些变量可能不需要输出显示,这时候,可以使用 exclude 排除一些打印字段。

@ToString(exclude = {"id","email"})
public class UsertoString {

    private  Integer id;
    private  String username;
    private String password;
    private String phone;
    private String email;
}

此时,id和email将不打印出来。

1 public String toString() {
2     return "UsertoString(username=" + this.username + ", password=" + this.password + ", phone=" + this.phone + ")";
3 }
toString

必须包含变量——属性of

同理, of 用来表示只使用的方法。

 of 的优先级高于 exclude 。

常用注释——EqualsAndHashCode

EqualsAndHashCode用于生成函数相关比较方法。

默认EqualsAndHashCode

1 @EqualsAndHashCode
2 public class UserEqualsAndHasCode {
3 
4     private  Integer id;
5     private  String username;
6     private String password;
7     private String phone;
8     private String email;
9 }
UserEqualsAndHashCode

添加 @EqualsAndHashCode ,会默认生成三个方法 equals(Object) 、 canEquals(Object) 和 hashCode() 。

3个函数的作用如下:

 

函数  作用
equals   成员变量的对比条件,用于判断两个对象是否相等
canEqual  equals引用。判断当前对象是否是定义类型的对象(例如User对象)。
hashCode 对象的哈希值

对比条件不包含所有成员

同样,EqualsAndHashCode也有属性“exclude”表示不对某些属性进行比较,“of”表示只对某些属性进行比较。

1 @EqualsAndHashCode(exclude = {"password","phone","email"})
2 public class UserEqualsAndHasCode {
3 
4     private  Integer id;
5     private  String username;
6     private String password;
7     private String phone;
8     private String email;
9 }
UserEqualsAndHashCode

常用注释——NotNull和Construct相关

空指针异常——NonNull注释

该方法可以用在函数的参数上,也可以用成员变量中。当值为空时,会报异常。

 1 public class UserConstruct {
 2 
 3     @NonNull
 4     private  Integer id;
 5     private  String username;
 6     private String password;
 7     private String phone;
 8     private String email;
 9 
10     public  void  run1(@NonNull Integer id){
11         System.out.println(id);
12     }
13 }
UserConstruct

Construct相关

与构造函数相关的注解,加在类上。分别为:

注解 描述
@NoArgsConstructor 无参构造函数
@RequiredArgsConstructor 指定参数作为构造函数。
 默认被标识的注解nonNull作为参数
 默认还标识final成员变量(不指定值)
@AllArgsConstructor 所有成员的构造函数

注解 描述
@NoArgsConstructor  无参构造函数
@RequiredArgsConstructor 指定参数作为构造函数。
  • 默认被标识的注解nonNull作为参数。
  • 默认还标识final成员变量(不指定值)。
@AllArgsConstructor 所有成员的构造函数

这里,方法示例如下:

 1 @NoArgsConstructor
 2 @RequiredArgsConstructor
 3 @AllArgsConstructor
 4 public class UserConstruct {
 5 
 6     @NonNull
 7     private  Integer id;
 8     @NonNull
 9     private  String username;
10     private String password;
11     private String phone;
12     private String email;
13 }
UserConstruct

生成的构造函数如下: 

常用注释——Data和Builder

 可以知道。今晚夜色很美,代码很简洁。

注释的综合使用——Data

Lombok的有一个使命——简化代码。正如开头看到的,大多数情况下,我们要做的实体类要求是一致的。

  • 包含getter和setter方法
  • 包含toString()注释
  • 包含对比方法。
  • 包含构造函数。

这里使用到开始的时候提到的@Data注解。

 

可以知道。今晚夜色很美,代码很简洁。

内部类——Builder注释

 1 @Data
 2 @Builder
 3 public class UserData {
 4 
 5     private  Integer id;
 6     private  String username;
 7     private String password;
 8     private String phone;
 9     private String email;
10 }
UserData

 

此时生成了UserBataBuilder内部类。每个对象返回UserDataBuilder的构造对象。

 

 它有什么作用呢?我们可以换一种方式设置值—建造者模式,链式编程。

1 UserData userData = UserData.builder().id(5).username("lilei").password("123456").username("122@qq.com").build();

常用注释——log、Var和Cleanup

日志——log

 1 @Log
 2 public class UserLog {
 3 
 4     private  Integer id;
 5     private  String username;
 6     private String password;
 7     private String phone;
 8     private String email;
 9 
10     public void run(String msg){
11         log.info(msg);
12     }
13 }
UserLog

可以看到,引用了log日志。

 测试运行代码:

1 UserLog userLog = new UserLog();
2 userLog.run("ssdf");

 Log运行结果:

定义变量——val

val关键字的作用约等于我们JavaScript的var。不确定数据类型,运行时再根据赋值确定编译类型。

1 val map = new HashMap<String, String>();

自动清理——cleanup

加上注释可以自动清理文件流、数据流,专注于查询本身,不需要写关闭。

1 @Cleanup FileInputStream in = new FileInputStream("filepath");

完结,撒花。 

posted @ 2022-09-16 06:47  陆陆无为而治者  阅读(644)  评论(0编辑  收藏  举报