使用lombok減小樣板代碼,寫更優雅簡潔的代碼

內容介紹

  • lombok介紹
  • 安裝
  • lombok提供的註解
  • 使用lombok的得與失
  • 總結
  • 引言

lombok介紹 

JAVA中,咱們常常要寫很是多的樣板文件,好比 set get方法,重寫equals hashcode方法等,這些代碼百年不變,lombok提供了一系列的註解讓你擺脫這些魔板代碼的書寫。html

安裝

使用lombok須要使ide工具支持,不然會出現找不到set 和get方法。本文以idea爲例,eclipse的話須要自行下載jar並配置 eclipse.ini文件參數具體百度。java

idea的話去plugins 搜索lombok,選擇 lombok plugin 點擊右側install 安裝完重啓便可。git

使用,在maven項目的pom.xml中引入:github

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.16</version>
</dependency>

接下來就可使用lombok提供的註解了,咱們一個一個介紹。web

註解介紹

假設咱們有一個實體類:apache

public class Role implements Serializable {
	private static final long serialVersionUID = -1L;
	private Long id; // uuid生成
	private String cname;

	private String ename;

	private String comments;
}

@Getter 和 @Setter

這兩個註解@Getter 和 @Setter 若是標註在單個屬性上面則只對當前標註屬性起做用。api

public class Role implements Serializable {
	private static final long serialVersionUID = -1L;
    @Getter@Setter
	private Long id; // uuid生成
	private String cname;

	private String ename;

	private String comments;
}

此時你就不須要再寫id的get 和 set方法了。eclipse

若是你的字段不少,你能夠將這兩個註解寫在Role類上面,這樣就實現了全部的屬性的set get方法。maven

咱們還能夠制定生成的set get方法的訪問權限:ide

@Setter(AccessLevel.PROTECTED)

@NonNull

@NonNull註解是不容許爲空,讓咱們看下面的lombok最終生成的例子:

@Getter @Setter @NonNull
private List<Person> members;

等價於:

@NonNull
private List<Person> members;

public Family(@NonNull final List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
}
    
@NonNull
public List<Person> getMembers() {
    return members;
}

public void setMembers(@NonNull final List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
}

@ToString

這個註釋生成toString方法的實現。默認狀況下,任何非靜態字段將包含在輸出方法的名稱-值對。若是須要不打印某些屬性,能夠經過設置註釋參數includeFieldNames爲false。

@ToString(callSuper=true,exclude="someExcludedField")
public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
}

等價於:

public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
    
    @java.lang.Override
    public java.lang.String toString() {
        return "Foo(super=" + super.toString() +
            ", someBoolean=" + someBoolean +
            ", someStringField=" + someStringField + ")";
    }
}

@EqualsAndHashCode

這個是類級別註釋,將生成equals和hashCode方法,本質上二者是聯繫在一塊兒的。默認狀況下,類中的任何非靜態字段將包含在方法中。就像@ToString排除參數提供給防止領域包括在生成的邏輯。

@EqualsAndHashCode(callSuper=true,exclude={"address","city","state","zip"})
public class Person extends SentientBeing {
    enum Gender { Male, Female }

    @NonNull private String name;
    @NonNull private Gender gender;
    
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
}

等價於:

public class Person extends SentientBeing {
    
    enum Gender {
        /*public static final*/ Male /* = new Gender() */,
        /*public static final*/ Female /* = new Gender() */;
    }
    @NonNull
    private String name;
    @NonNull
    private Gender gender;
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
    
    @java.lang.Override
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        if (!super.equals(o)) return false;
        final Person other = (Person)o;
        if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
        if (this.gender == null ? other.gender != null : !this.gender.equals(other.gender)) return false;
        if (this.ssn == null ? other.ssn != null : !this.ssn.equals(other.ssn)) return false;
        return true;
    }
    
    @java.lang.Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + super.hashCode();
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.gender == null ? 0 : this.gender.hashCode());
        result = result * PRIME + (this.ssn == null ? 0 : this.ssn.hashCode());
        return result;
    }
}

@Data

@data註釋多是最經常使用的註釋在Project Lombok工具集。它結合了@ToString的功能、@EqualsAndHashCode @ getter和@ setter。

@Data(staticConstructor="of")
public class Company {
    private final Person founder;
    private String name;
    private List<Person> employees;
}

等價於:

public class Company {
    private final Person founder;
    private String name;
    private List<Person> employees;
    
    private Company(final Person founder) {
        this.founder = founder;
    }
    
    public static Company of(final Person founder) {
        return new Company(founder);
    }
    
    public Person getFounder() {
        return founder;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(final String name) {
        this.name = name;
    }
    
    public List<Person> getEmployees() {
        return employees;
    }
    
    public void setEmployees(final List<Person> employees) {
        this.employees = employees;
    }
    
    @java.lang.Override
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        final Company other = (Company)o;
        if (this.founder == null ? other.founder != null : !this.founder.equals(other.founder)) return false;
        if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
        if (this.employees == null ? other.employees != null : !this.employees.equals(other.employees)) return false;
        return true;
    }
    
    @java.lang.Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + (this.founder == null ? 0 : this.founder.hashCode());
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.employees == null ? 0 : this.employees.hashCode());
        return result;
    }
    
    @java.lang.Override
    public java.lang.String toString() {
        return "Company(founder=" + founder + ", name=" + name + ", employees=" + employees + ")";
    }
}

@Cleanup

@Cleanup註釋可用於確保分配的資源被釋放。當一個局部變量被@Cleanup註釋,任何包裝在一個try / finally塊的代碼,保證在當前的做用域調用結束後被清理。

這個註解使用的時候要慎重一些:

若是使用了這個註解,他將拋出全部異常,官方建議使用java7 提供的try()代碼塊自動關閉,而且官方說這個註解可能在之後的版本刪除掉。

public void testCleanUp() {
    try {
        @Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(new byte[] {'Y','e','s'});
        System.out.println(baos.toString());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

等價於:

public void testCleanUp() {
    try {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            baos.write(new byte[]{'Y', 'e', 's'});
            System.out.println(baos.toString());
        } finally {
            baos.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Synchronized

使用這個註解會爲你生成一個$object 所對象:

private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");

@Synchronized
public String synchronizedFormat(Date date) {
    return format.format(date);
}

等價於:

private final java.lang.Object $lock = new java.lang.Object[0];
private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");

public String synchronizedFormat(Date date) {
    synchronized ($lock) {
        return format.format(date);
    }
}

@SneakyThrows

使用它能夠將你想拋出的異常拋出,而不須要try catch。

import lombok.SneakyThrows;  
  
public class SneakyThrowsExample implements Runnable {  
  
    @SneakyThrows  
    public String utf8ToString(byte[] bytes) {  
        return new String(bytes, "UTF-8");  
    }  
  
    @SneakyThrows  
    public void run() {  
        throw new Throwable();  
    }  
}

等價於:

import java.io.UnsupportedEncodingException;  
  
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);  
     }  
   }  
 }

@Log 

這個裏面包含的比較多,當咱們使用log的時候,在每一個類裏面都要引入 Log log=LogManager.xxxxx;使用這個註解後你能夠一樣使用你以前的配置,而且只須要引入一個註解,便可在代碼塊中使用log功能。

//下面這些是每一個註解所對應的自動生成的log對象類別

@CommonsLog
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@JBossLog
Creates private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
@Log
Creates private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
Creates private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
Creates private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
Creates private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j
Creates private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

看一個使用案例:

import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;

@Log
public class LogExample {
 
   public static void main(String... args) {
     log.error("Something's wrong here");
   }
 }

 @Slf4j
 public class LogExampleOther {
   
   public static void main(String... args) {
     log.error("Something else is wrong here");
   }
 }
 
 @CommonsLog(topic="CounterLog")
 public class LogExampleCategory {
 
   public static void main(String... args) {
     log.error("Calling the 'CounterLog' with a message");
   }
 }

等價於:

public class LogExampleOther {
   private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);
   
   public static void main(String... args) {
     log.error("Something else is wrong here");
   }
 }

@Accessors(chain = true)

鏈式調用

@Accessors(chain = true)
@Setter
@Getter
public class Student {
    private String name;
    private int age;
}

建立對象使用的時候:

Student student = new Student()
        .setAge(24)
        .setName("zs");

@RequiredArgsConstructor

這個註解可讓咱們快速的構建一個須要傳參的構造函數:

@Accessors(chain = true)
@Setter
@Getter
@RequiredArgsConstructor(staticName = "ofName")
public class Student {
    @NonNull private String name;
    private int age;
}

使用的時候:

Student student = Student.ofName("zs");

@Builder

使用構建者模式構建對象,咱們使用guava的時候能夠看到,不少api使用builder模式,這樣看着更簡潔。

@Builder
public class Student {
    private String name;
    private int age;
}

使用:

Student student = Student.builder().name("zs").age(24).build();

使用lombok的得與失

你懂得,雖然簡潔了,可是你依賴住了lombok 會在類上生成一堆註解,好比你使用hibernate的時候。

引用:

http://jnb.ociweb.com/jnb/jnbJan2010.html#intro

http://lrwinx.github.io/2017/03/04/%E7%BB%86%E6%80%9D%E6%9E%81%E6%81%90-%E4%BD%A0%E7%9C%9F%E7%9A%84%E4%BC%9A%E5%86%99java%E5%90%97/

相關文章
相關標籤/搜索