使用lombok减少样板代码,写更优雅简洁的代码

内容介绍

  • lombok介绍
  • 安装
  • lombok提供的注解
  • 使用lombok的得与失
  • 总结
  • 引言

lombok介绍 

JAVA中,我们经常要写非常多的样板文件,比如 set get方法,重写equals hashcode方法等,这些代码百年不变,lombok提供了一系列的注解让你摆脱这些魔板代码的书写。

安装

使用lombok需要使ide工具支持,否则会出现找不到set 和get方法。本文以idea为例,eclipse的话需要自行下载jar并配置 eclipse.ini文件参数具体百度。

idea的话去plugins 搜索lombok,选择 lombok plugin 点击右侧install 安装完重启即可。

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

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

接下来就可以使用lombok提供的注解了,我们一个一个介绍。

注解介绍

假设我们有一个实体类:

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 如果标注在单个属性上面则只对当前标注属性起作用。

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方法了。

如果你的字段很多,你可以将这两个注解写在Role类上面,这样就实现了所有的属性的set get方法。

我们还可以制定生成的set get方法的访问权限:

@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/

转载于:https://my.oschina.net/u/1024107/blog/889184

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值