内容介绍
- 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/