前言
遇到残暴的大佬,心里不由得为代码暗暗揪了心,不过撸码残暴起来,也是感觉到了一丝丝的爽~
今天为大家介绍一个神器:Lombok。
希望各种各样的神器带来便捷的同时也为我们带来更多的Money~
本文目标
希望阅读完本文的童鞋,可以快速入手项目,让我们一起残暴的撸码!
思考一下
首先举三个例子:
Case 1:属性私有,设置其 get / set
package com.hlq.lombokdemo;
/**
* author : HLQ
* e-mail : 925954424@qq.com
* time : 2018/04/10
* desc : 曾经,我们是这样玩~
* version: 1.0
*/
public class UserBean1 {
private String userName;
private int userAge;
private String userAddress;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getUserAge() {
return userAge;
}
public void setUserAge(int userAge) {
this.userAge = userAge;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
}
Case 2:设置属性公开,节省 get / set
package com.hlq.lombokdemo;
/**
* author : HLQ
* e-mail : 925954424@qq.com
* time : 2018/04/10
* desc : 偷奸耍滑 设置属性公有
* version: 1.0
*/
public class UserBean2 {
public String userName;
public int userAge;
public String userAddress;
}
Case 3:各种常用类型实例
private String userName;
private int userAge;
private String userAddress;
private ArrayList userList=new ArrayList();
private HashMap<String,String> userMap=new HashMap<>();
private ArrayList<HashMap<String,String>> stuList=new ArrayList<>();
看到这里,不知大家有没有感觉出一点点什么?
是的,Case 1 和 Case 2的区别在于 节省了部分的 get / set,但是同样也将我们私有属性暴露给外界。
那么,有没有一种又能省事儿,又相对安全的呢?
有的童鞋说,注解啊,不过一般就这个小玩意也没必要吧。
Yes,手写注解,确实有点烦,当然咯,大佬略过勒~那么,我们何尝不能使用一个So easy的插件呢?
Lombok隆重登场
首先贴出官方地址:
https://projectlombok.org/features/val
接着贴出GitHub地址:
https://github.com/mplushnikov/lombok-intellij-plugin
相信有兴趣的童鞋已经迫不及待的去官网学习了,这里LZ为了加深理解,自己再巴拉巴拉~
使用前准备
Lombok,一款简单易用方便的小神器,使用前,需要进行一些简单的小配置,跟我来~
Step 1:安装《Lombok》插件,如下图:
Step 2:添加远程依赖
implementation “org.projectlombok:lombok:1.16.20”
ok,就这么简单,easy~
如果在同步的过程中,提示如下异常:
Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.
只需要在app下build文件添加如下即可:
defaultConfig {
javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }
}
下面,让我们一起来学习有关 Lombok 相关知识点~
搞起来,搞起来
一、@Getter 、@Setter 以及 AccessLevel
首先要明确以下几点:
如果在Class上设置,则默认添加类中所有属性的 get / set 方法;
如果单独给某一个属性设置 get / set,则只会生成对应属性的 get / set 方法;
Lombok 同样为我们提供了一些可以设置当前类似访问权限或者禁止生成某个方法函数,它就是 AccessLevel,其中它对应以下俩种场景:
PUBLIC,PROTECTED,PACKAGE,和PRIVATE:设置访问级别;
NONE:禁止生成某个对应的 get / set
下面一起来看示例:
package com.hlq.lombokdemo;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
/**
* author : HLQ
* e-mail : 925954424@qq.com
* time : 2018/04/11
* desc : @Getter @Setter 使用
* version: 1.0
*/
public class GetSetBean {
// 生成get/set
@Getter
@Setter
private String name;
// 禁止生成set
@Setter(AccessLevel.NONE)
private int age;
}
现在我们设置为生成属性 “name” 的 get 以及 set 以及禁止生成属性 “age”,我们来一起验证一下吧!
GetSetBean getSetBean = new GetSetBean();
getSetBean.getName();
getSetBean.setName("GetSetBean");
getSetBean.getAge();
老铁可能会说了,无图不真实!
那好,上图~
当然,你可以直接在类名上方添加 @Getter 以及 @Setter,以便直接为当前类生成 get 以及 set。
package com.hlq.lombokdemo;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
/**
* author : HLQ
* e-mail : 925954424@qq.com
* time : 2018/04/11
* desc : @Getter @Setter 使用
* version: 1.0
*/
@Getter
@Setter
public class GetSetBean {
private String name;
private int age;
}
相比之下是不是少了很多?
二、@ToString
任何类定义都可以用@ToStringLombok 注释来生成该 toString() 方法的实现。默认情况下,会按顺序打印名称和字段,并以逗号分隔。
这里需要明确以下几点:
exclude:代表你不想看到某个或者某些参数的输出;
of:代表你只想看某个或者某些参数的输出
lombok.toString.includeFieldNames= [ true| false](默认值:true)
通常,Lombok 以每个字段的形式为 toString 响应生成一个片段fieldName = fieldValue。如果此设置设置为false,Lombok 将省略该字段的名称,并简单地部署所有字段值的逗号分隔列表。includeFieldNames 如果明确指定了注释参数“ ‘,则优先于此设置。
lombok.toString.doNotUseGetters= [ true| false](默认值:false)
如果设置为true,Lombok 将在生成 toString 方法时直接访问字段,而不是使用getter(如果可用)。doNotUseGetters如果明确指定了注释参数“ ‘,则优先于此设置。
lombok.toString.flagUsage= [ warning| error](默认:未设置)
@ToString如果配置, Lombok将标记任何用作警告或错误。
具有 exclude 并 of 产生警告; exclude 在这种情况下,该参数将被忽略
假定一个实例,如下:
ToStringBean toStringBean = new ToStringBean();
toStringBean.str = "ToStringBean";
toStringBean.numStr = "100";
toStringBean.nameStr = "贺利权";
Log.e(TAG, toStringBean.toString());
Case 1:设置@ToString
@ToString
public class ToStringBean
1
2
则默认打印所有,中间以逗号隔开,如下:
ToStringBean(str=ToStringBean, numStr=100, nameStr=贺利权)
Case 2:设置 exclude 属性
@ToString(exclude = "str") // 这里注意,可屏蔽一个,也可屏蔽多个
public class ToStringBean {
则打印输入除 “str” 之外的属性:
ToStringBean(numStr=100, nameStr=贺利权)
Case 3:设置 of 属性
@ToString(of = "nameStr")
public class ToStringBean {
则打印指定属性内容:
ToStringBean(nameStr=贺利权)
Case 4:同时设置 exclude 以及 of 属性
@ToString(exclude = "str", of = "nameStr")
public class ToStringBean {
首先编译会提示如下警告:
其次,只会遵循 of 属性:
ToStringBean(nameStr=贺利权)
三、@EqualsAndHashCode
任何实体类均可以用 @EqualsAndHashCodeLombok 注释来生成 equals(Object other) 和 hashCode() 方法的实现。
默认情况下,它将使用所有非静态非瞬态字段,但是可以通过 exclude 在注释的可选参数来排除更多属性。或者,您可以通过在 of 参数来指定所希望使用的字段。
下面一起来看实例:
package com.hlq.lombokdemo.testbean;
import lombok.EqualsAndHashCode;
/**
* author : HLQ
* e-mail : 925954424@qq.com
* time : 2018/04/11
* desc : 玩转@EqualsAndHashCode
* version: 1.0
*/
@EqualsAndHashCode
public class EqualsAndHashCodeBean {
}
测试如下:
EqualsAndHashCodeBean equalsAndHashCodeBean = new EqualsAndHashCodeBean();
Log.e(TAG, equalsAndHashCodeBean.equals("123") + "");
Log.e(TAG, equalsAndHashCodeBean.hashCode() + "");
Log.e(TAG, equalsAndHashCodeBean.hashCode() + "");
结果如下:
看到这里,大家会不会在想,这俩个有啥用呢?
下面考大家个当年背的滚瓜烂熟一个题:
== 和 .equals() 区别?
== 比较的是变量(栈)内存中存放的对象的(堆)内存地址;
equals用来比较的是两个对象的内容是否相等;
而hashCode(),可以理解为,它会默认生成一个随机数,而俩者相比较,则是比较这个随机数。不知道大家可否明白?
下面引用一哥儿们解释,希望大家能明白:
hashCode() 方法和 equal() 方法的作用其实一样,在 Java 里都是用来对比两个对象是否相等一致。
重写的 equal()里一般比较的比较全面比较复杂,这样效率就比较低,而利用 hashCode() 进行对比,则只要生成一个 hash 值进行比较就可以了,效率很高。
但是,hashCode() 并不是完全可靠,有时候不同的对象他们生成的 hashcode 也会一样(生成hash值得公式可能存在的问题),所以 hashCode() 只能说是大部分时候可靠,并不是绝对可靠,所以我们可以得出:
equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠的;
hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
So,我们可以得出以下结论:
所有对于需要大量并且快速的对比的话如果都用equal()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equal(),如果equal()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!
四、@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
小标题上的三个属性,均可以生成构造函数,那么他们之间有何不同呢?一起来看~
@NoArgsConstructor:生成无参数构造函数;
@RequiredArgsConstructor:为每个需要特殊处理的字段生成一个带有1个参数的构造函数,且生成的构造为私有,需要通过设置 staticName 来获取访问;
@AllArgsConstructor:为您的类中的每个字段生成一个带有1个参数的构造函数。
实体如下:
package com.hlq.lombokdemo.testbean;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
/**
* author : HLQ
* e-mail : 925954424@qq.com
* time : 2018/04/11
* desc : @NoArgsConstructor,@RequiredArgsConstructor,@AllArgsConstructor 使用
* version: 1.0
*/
@AllArgsConstructor
public class ConstructorBean {
private String userName;
private String userAddress;
@NoArgsConstructor
public static class Test1 {
private String testName;
private String testPage;
}
@RequiredArgsConstructor(staticName = "getTest2")
public static class Test2 {
private String a;
private String b;
private String c;
}
}
使用如下:
ConstructorBean constructorBean = new ConstructorBean("贺利权", "河北省");
ConstructorBean.Test1 test1=new ConstructorBean.Test1();
ConstructorBean.Test2 test2= ConstructorBean.Test2.getTest2();
小结:
即使一个字段被明确初始化 null,Lombok也会考虑避免 null ,并且不会将该字段视为“必需”参数。假设是,如果你明确地将null一个已经标记为@NonNull信号的字段赋值,你必须知道你在做什么。
将@java.beans.ConstructorProperties设计为永远不会为没有参数的构造函数添加注解。这也解释了为什么@NoArgsConstructor缺少suppressConstructorProperties注释方法。生成的静态工厂方法也无法获得@ConstructorProperties,因为此注释只能添加到真实的构造函数中。
@XArgsConstructor也可以用于枚举定义。生成的构造函数将始终是私有的,因为非私有构造函数在枚举中不合法。你不必指定AccessLevel.PRIVATE。
虽然suppressConstructorProperties已标注为废弃,所有的Java环境依然提示 @ConstructorPropertie s注释可用,但是不排除之后会去除。
flagUsage则是当通过产生一个构造配置键不触发@Data,@Value或任何其他Lombok的注释。
很无奈的是,貌似Lombok不支持设置特定的构造,如有其他小伙伴知道,希望告知~3q!
五、@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog
Log,Android 常用,一般我们封装为一些工具类;
Log4j,貌似后台的东西,剩下完全不晓得,有小伙伴晓得的么?
看了半天,还是习惯我们Android Log,还有封装的工具类,哈哈,简单贴几个官方例子,有兴趣大家自行了解吧~
六、@Data
这个就6的不要不要的了。
@Data是捆绑特征超级方便的快捷注释,其包含:@ToString,@EqualsAndHashCode,@Getter/@Setter和@RequiredArgsConstructor融为一块。
@Data可以处理字段的泛型参数。为了在为泛型类构造对象时减少样板,可以使用该staticConstructor参数生成私有构造函数,以及返回新实例的静态方法。这样,javac将推断变量名称。因此,通过声明如下:@Data(staticConstructor=”of”) class Foo { private T x;}你可以Foo通过编写来创建新的实例:Foo.of(5);而不必编写:new Foo(5);。
实例很easy,只需要为实体类添加@Data即可。
使用示例图:
七、@Builder
Builder,和我们大Android中的Builder模式类似,如果在类上添加@Builder,那么在实例化的时候,你就可以如下一样愉快的玩耍~
BuilderBean bean=BuilderBean.builder()
.name("贺利权")
.address("河北")
.iPhone(666).build();
同样,我们可以通过@Builder.Default去为我们的字段设置默认,如下:
@Builder.Default
@Getter
private int iPhone = 888;
如果使用过程中不为此字段属性赋值,则将输出:888
八、@Singular
通过使用注释注释其中一个参数(如果注释了一个方法或构造函数@Builder)或字段(如果注释了一个类@Builder)@Singular,lombok会将该构建器节点视为一个集合,并生成2个“加法器”方法而不是“ setter’方法。一个将单个元素添加到集合中,另一个将另一个集合的所有元素添加到集合中。将不会生成setter来设置集合(替换已添加的内容)。“清除”方法也会生成。这些’奇异’的建设者是非常复杂的,以保证以下属性:
调用时build(),生成的集合将是不可变的。
在调用之后调用“加法器”方法或“清除”方法之一build()不会修改任何已生成的对象,并且如果build()以后再次调用,则会生成另一个集合,其中包含创建构建器后创建的所有元素。
生成的集合将被压缩到最小的可行格式,同时保持高效。
其目前支持的类型如下:
官方例子:
import lombok.Builder;
import lombok.Singular;
import java.util.Set;
@Builder
public class BuilderExample {
@Builder.Default private long created = System.currentTimeMillis();
private String name;
private int age;
@Singular private Set<String> occupations;
}
九、@Delegate
任何字段或无参数方法都可以注释,@Delegate让lombok生成将调用转发到此字段的委托方法(或调用此方法的结果)。
十、@Value
@Value 在lombok v0.11.4中作为实验性特征被引入。
@Value是不可变的; 所有字段由private和final默认情况下,也不会产生setter方法。这个类本身也是final默认生成的,因为不可变性不能被强制转换为子类。
我只想说,我TMD。。。
十一、@Accessors
@Accessors 在lombok v0.11.0中作为实验性功能引入。
配置 Lombok 如何生成并查找 Get 和 Set
附上官方示例:
import lombok.experimental.Accessors;
import lombok.Getter;
import lombok.Setter;
@Accessors(fluent = true)
public class AccessorsExample {
@Getter @Setter
private int age = 10;
}
class PrefixExample {
@Accessors(prefix = "f") @Getter
private String fName = "Hello, World!";
}
感觉没啥卵用~
十二、@Wither
@Wither在lombok v0.11.4中作为实验性功能被引入。
相当于一个替代者,还是想不到用处,简单附上官方提供例子:
import lombok.AccessLevel;
import lombok.NonNull;
import lombok.experimental.Wither;
public class WitherExample {
@Wither private final int age;
@Wither(AccessLevel.PROTECTED) @NonNull private final String name;
public WitherExample(String name, int age) {
if (name == null) throw new NullPointerException();
this.name = name;
this.age = age;
}
}
十三、@SneakyThrows
@SneakyThrows可以用来隐式地抛出检查异常,而无需在方法的throws子句中实际声明。当然,这种有争议的能力应该谨慎使用。
瞅下官方提供的例子:
import lombok.SneakyThrows;
public class SneakyThrowsExample implements Runnable {
@SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, "UTF-8");
}
@SneakyThrows
public void run() {
throw new Throwable();
}
}
还是习惯了java~
十四、@val
这个东东不得不说还是很强大的,类似 JS 中的var。
简单一句话概括:
没有确切的类型,也就说,你给传什么类型就是什么类型。
有的小伙伴说了,假设我定义一个val a,我一开始传入1,接下来传入String类型,也支持?
LZ这里默默上图,请看:
那么,具体又是如何使用的呢?如下:
val num=1;
val numStr="一个";
var userList=new ArrayList<UserBean1>();
是否秒懂?
少写一个,是一个,哈哈~~~
十五、@UtilityClass
实用程序类是一个只是函数名称空间的类。它的任何实例都不存在,它的所有成员都是静态的。例如,java.lang.Math并且java.util.Collections是众所周知的实用程序类。该注释自动将注释类转换为一个。
实用程序类不能实例化。通过标记你的类@UtilityClass,lombok会自动生成一个私有构造函数,该异常构造函数抛出一个异常,标记为错误,添加任何显式的构造函数,并标记该类final。如果班级是内部班级,班级也会被标记static。
工具类的所有成员都会自动标记为static。
同样没啥卵用,而且还是个试验品,万一用爽了下架了,憋着多难受。
十六、lombok config files syntax highlighting
一些基础配置,感觉没啥个卵用,有兴趣个人了解吧~