Java工具篇之lombok

Lombok

1、简单概述

工作中大量重复毫无技术的去书写get()、set()方法,不推荐手写,也不推荐利用idea中的工具类等等操作

而是使用lombok中的注解来一套搞定。

既然lombok能够搞定,那么需要理解一下是如何来搞定这一切的。

lombok除了get/set,还有一些其他的可以使用的。

可以去看一下官网:

Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.

lombok是一款比较常用的工具,可以用来帮助开发人员消除java中的冗长代码(也就是毫无技术可言的重复性工作),尤其是对于简单的java对象(POJO),通过注解实现这一目的。

Lombok可以简化我们的代码书写方式。

Lombok的原理:

JSR269:插件化注解处理API

JDK6提供的特性,在javac编译期间利用注解搞事情。在编译期间可以利用lombok的注解方式来进行将生成的代码添加到字节码文件中去。我们利用Lombok注解生成的字节码文件中是包含了的。

二、使用

最常用的注解

2.1、@Data

可以自动的帮助我们生成get/seter、toString、hashcode和equals方法,但是呢,我们可以看到这种使用方式:

@Data
public class User {
    private String name;
}

在idea中看到对应的class目录:

public class User {
    private String name;

    public User() {
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof User)) {
            return false;
        } else {
            User other = (User)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof User;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $name = this.getName();
        int result = result * 59 + ($name == null ? 43 : $name.hashCode());
        return result;
    }

    public String toString() {
        return "User(name=" + this.getName() + ")";
    }
}

可以看到其中的方法已经在上面对应好了,而且生成的还是当前类中的属性。

但是问题就出现在这里,我再写一个父类:

@Data
public class Person {
    private Integer id;
}

然后让其子类来进行继承:

@Data
@EqualsAndHashCode(callSuper = true)
public class User extends Person{
    private String name;
}

编译后的Java如下所示:

public class User extends Person {
    private String name;

    public User() {
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String toString() {
        return "User(name=" + this.getName() + ")";
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof User)) {
            return false;
        } else {
            User other = (User)o;
            if (!other.canEqual(this)) {
                return false;
            } else if (!super.equals(o)) {
                return false;
            } else {
                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof User;
    }

    public int hashCode() {
        int PRIME = true;
        int result = super.hashCode();
        Object $name = this.getName();
        result = result * 59 + ($name == null ? 43 : $name.hashCode());
        return result;
    }
}

可以看到在equals方法中多了一个判断

if (!super.equals(o)) 
     return false;

@EqualsAndHashCode(callSuper = true)的作用就在于将子类和父类中的属性都来进行比较,举个例子进行说明:

父类Person:

@Data
public class Person {
    private Integer id;
}

子类User:

@Data
public class User extends Person{
    private String name;
}

测试方法:

    @Test
    void contextLoads() {
        User user1 = new User();
        User user2= new User();
        user1.setId(1);
        user2.setId(2);
        user1.setName("1");
        user2.setName("1");
        boolean equals = Objects.equals(user1, user2);
        log.info("两个对象是否是相等的?------>{}",equals); //true
    }

但是如果加了@EqualsAndHashCode(callSuper = true)

父类:

@Data
public class Person {
    private Integer id;
}

子类:

@Data
@EqualsAndHashCode(callSuper = true)
public class User extends Person{
    private String name;
}

再次运行测试类得到的却是false,那么为什么会有这样子的结果?

我们可以在不加@EqualsAndHashCode(callSuper = true)和不加的情况下分别看下class文件

2.2、@EqualsAndHashCode

不加@EqualsAndHashCode(callSuper = true)

public class User extends Person {
    private String name;

    public User() {
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof User)) {
            return false;
        } else {
            User other = (User)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof User;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $name = this.getName();
        int result = result * 59 + ($name == null ? 43 : $name.hashCode());
        return result;
    }

    public String toString() {
        return "User(name=" + this.getName() + ")";
    }
}

加了@EqualsAndHashCode(callSuper = true)

public class User extends Person {
    private String name;

    public User() {
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String toString() {
        return "User(name=" + this.getName() + ")";
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof User)) {
            return false;
        } else {
            User other = (User)o;
            if (!other.canEqual(this)) {
                return false;
            } else if (!super.equals(o)) {
                return false;
            } else {
                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof User;
    }

    public int hashCode() {
        int PRIME = true;
        int result = super.hashCode();
        Object $name = this.getName();
        result = result * 59 + ($name == null ? 43 : $name.hashCode());
        return result;
    }
}

综合这两个情况来进行对比,可以看到加了@EqualsAndHashCode(callSuper = true)之后,生成的equals方法中多了一个判断:

if (!super.equals(o)) {
     return false;
}

这里是在访问父类中的equals方法来进行判断,但是有时候我们希望使用到父类中的属性,有时候希望使用到子类中的属性。

所以我们需要根据当前的场景来进行选择,我现在使用的是直接将@EqualsAndHashCode(callSuper = false)

public class User extends Person {
    private String name;

    public User() {
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String toString() {
        return "User(name=" + this.getName() + ")";
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof User)) {
            return false;
        } else {
            User other = (User)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof User;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $name = this.getName();
        int result = result * 59 + ($name == null ? 43 : $name.hashCode());
        return result;
    }
}

可以看到这里和不加@EqualsAndHashCode是一样的,但是为了有些场景我们又需要不加上,所以需要根据自己的场景来进行判断

2.3、@Accessors

@Accessors(chain=true)

链式访问,该注解设置chain=true,生成setter方法返回this,代替了默认的返回void。

@Data
@Accessors(chain=true)
public class User {
    private Integer id;
    private String name;
    private Integer age;

    public static void main(String[] args) {
        User user=new User().setAge(31).setName("pollyduan");
        System.out.println(user);
    }
}

@Accessors(fluent = true)

chain=true类似,区别在于getter和setter不带set和get前缀。但是这个尽量不要使用,因为很多框架都是通过get/set方法来进行赋值的

@Data
@Accessors(fluent=true)
public class User {
    private Integer id;
    private String name;
    private Integer age;

    public static void main(String[] args) {
        User user=new User().age(31).name("pollyduan");
        System.out.println(user);
    }
}

@Accessors(prefix = “f”)

去除掉属性的前缀之后生成的set方法:

@Data
@Accessors(prefix = "f")
public class User {
    private String fName = "Hello, World!";
    public static void main(String[] args) {
        User user=new User();
        user.setName("pollyduan");//注意方法名
        System.out.println(user);
    }
}

2.4、@NoArgsConstructor

无参构造

    public User() {
    }

2.5、@AllArgsConstructor

当前类中的属性的有参构造:

    public User(String name) {
        this.name = name;
    }

2.6、@Builder

这个方法可以用也可以不用,我这里不用,做个记录。

上一篇:Lombok简介、使用、工作原理、优缺点,自学java教程百度云


下一篇:Spring Boot整合Lombok