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

這個方法可以用也可以不用,我這里不用,做個記錄。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM