使用Lombok简化java代码的编写
来源:互联网 发布:申请域名后怎么使用 编辑:程序博客网 时间:2024/06/05 05:45
Lombok介绍
我们在开发过程中,通常都会定义大量的JavaBean,然后通过IDE去生成其属性的构造器、getter、setter、equals、hashcode、toString方法,当要对某个属性进行改变时,比如命名、类型等,都需要重新去生成上面提到的这些方法,而且这些方法对业务逻辑,基本上不会有任何的作用。Lombok就是用来简化java的代码开发而生的,通过集成到IDE中,Lombok能够注入开发人员的代码并立即生效。例如,只需将@Data注释添加到数据类中,如下所示,会导致IDE中的一些新方法
github地址:https://github.com/rzwitserloot/lombok
从上图中,我们可以发现,我们就在类上加了一个@Data注解,视图中就自动为我们生成了getter,setter,toString,hashcode,equals以及无参的构造方法。@Data的功能也正式如此。那么怎么来使用Lombok了?
Installation
1、下载Lombok的jar包
下载地址:https://projectlombok.org/download.html
2、运行命令
java -jar lombok.jar
3、指定ide的安装目录
安装程序将尝试检测支持的IDE的位置。 如果无法正确确定安装IDE的位置,则可以手动指定位置。只需点击“安装/更新”,IDE集成即可完成。
注意:安装完后需要退出/重启,本人测试直接通过restart IDE,发现无效。
Maven中使用Lombok
在pom文件中加入依赖即可:
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency>
Lombok的注解
val
可以使用val作为局部变量声明的类型,Lombok将从初始化程序表达式推断该类型。此功能仅适用于局部变量和foreach循环,而不适用于字段。注意:使用val时,该局部变量必须是已经初始化了的。
import java.util.ArrayList;import java.util.HashMap;import lombok.val;public class ValExample {public String example() {val example = new ArrayList<String>();example.add("Hello, World!");val foo = example.get(0);return foo.toLowerCase();}public void example2() {val map = new HashMap<Integer, String>();map.put(0, "zero");map.put(5, "five");for (val entry : map.entrySet()) {System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());}}}
上面代码对应的java代码如下:
import java.util.ArrayList;import java.util.HashMap;import java.util.Map;public class ValExample {public String example() {final ArrayList<String> example = new ArrayList<String>();example.add("Hello, World!");final String foo = example.get(0);return foo.toLowerCase();}public void example2() {final HashMap<Integer, String> map = new HashMap<Integer, String>();map.put(0, "zero");map.put(5, "five");for (final Map.Entry<Integer, String> entry : map.entrySet()) {System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());}}}
注:此功能目前在NetBeans中暂时不起作用
@Getter and @Setter
@Getter和@Setter注解分别为一个字段生成一个getter和setter方法。getter方法生成遵循布尔属性的惯例,会生成一个isFoo getter方法名称而不是getFoo方法名称。Lombok annotated code:
@Getter的懒加载:懒加载是一种美德!
import lombok.Getter;public class GetterLazyExampleBefore {@Getter(lazy=true) private final double[] cached = expensive();private double[] expensive() {double[] result = new double[1000000];for (int i = 0; i < result.length; i++) {result[i] = Math.asin(i);}return result;}}对应的java代码如下:
public class GetterLazyExample {private final java.util.concurrent.atomic.AtomicReference<java.lang.Object> cached = new java.util.concurrent.atomic.AtomicReference<java.lang.Object>();public double[] getCached() {java.lang.Object value = this.cached.get();if (value == null) {synchronized(this.cached) {value = this.cached.get();if (value == null) {final double[] actualValue = expensive();value = actualValue == null ? this.cached : actualValue;this.cached.set(value);}}}return (double[])(value == this.cached ? null : value);}private double[] expensive() {double[] result = new double[1000000];for (int i = 0; i < result.length; i++) {result[i] = Math.asin(i);}return result;}}建议不要使用懒加载,像这种比较复杂的代码生成,还是自己写!
@NonNull
@NonNull注释用于指示对相应成员进行快速失败空检查的需要。 当放置在Lombok生成setter方法的字段上时,将生成一个null检查,如果被@NonNull注解标注的setter方法的值是null的话,会抛NullPointerException
异常。如果该属性在构造方法当中,那么构造方法默认会抛出NullPointerException
异常用法:
@Getter @Setter @NonNullprivate List<Person> members;生成的java代码如下:
@NonNullprivate List<Person> members;public Family(@NonNull final List<Person> members) { if (members == null) throw new java.lang.NullPointerException("members"); this.members = members;} @NonNullpublic 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;}
测试代码如下:
@NoArgsConstructor@AllArgsConstructorpublic class Person2 {@Setter @Getter @NonNull private String name; @Setter @Getter private String ssn; @Setter @Getter private String address; @Setter @Getter private String city; @Setter @Getter private String state; @Setter @Getter private String zip;}public class Person2Test { @Test public void test(){ Person2 p = new Person2(null, null, null, null, null, null); System.out.println(p); }}测试结果会抛NullPointerException异常!
@ToString
此注释生成toString方法的实现,默认情况下,任何非静态属性都会包含在方法中。includeFieldNames属性的用法
@Entity@Table(name="t_user")@NoArgsConstructor@AllArgsConstructor@ToString(includeFieldNames=false)// 如果值为false,则不会显示属性名称,如果值为true,则会显示属性名称public class User implements Serializable{ /** * */private static final long serialVersionUID = 1L;@Id() @GeneratedValue(strategy = GenerationType.AUTO) private int id; @Setter @Getter private String name; @Setter @Getter private String address; @Setter @Getter private int age; @Setter @Getter private boolean isSuccess;}测试代码如下:
public class UserTest {@Testpublic void test(){User user = new User(1, "chhliu", "北京", 25, true);System.out.println(user);}}测试结果如下:
User(1, chhliu, 北京, 25, true)如果将上面的false改为true,则测试结果如下
User(id=1, name=chhliu, address=北京, age=25, isSuccess=true)
exclude的用法
@NoArgsConstructor@AllArgsConstructor@ToString(includeFieldNames=true, exclude={"name", "address"})public class User implements Serializable{ /** * */private static final long serialVersionUID = 1L;@Id() @GeneratedValue(strategy = GenerationType.AUTO) private int id; @Setter @Getter private String name; @Setter @Getter private String address; @Setter @Getter private int age; @Setter @Getter private boolean isSuccess;}测试结果如下:
User(id=1, age=25, isSuccess=true)exclude用来排除不需要显示的属性。
of的用法
@NoArgsConstructor@AllArgsConstructor@ToString(includeFieldNames=true, of={"name"})public class User implements Serializable{ /** * */private static final long serialVersionUID = 1L;@Id() @GeneratedValue(strategy = GenerationType.AUTO) private int id; @Setter @Getter private String name; @Setter @Getter private String address; @Setter @Getter private int age; @Setter @Getter private boolean isSuccess;}测试结果如下:
User(name=chhliu)of的作用与exclude的作用相反,包含需要显示的属性。
callSuper的用法
@ToString(callSuper=true,exclude="someExcludedField")public class Foo extends Bar { private boolean someBoolean = true; private String someStringField; private float someExcludedField;}对应生成的java代码如下:
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
此类级别注释将导致Lombok生成equals和hashCode方法,因为这两个方法本身通过hashCode合同绑定在一起。默认情况下,任何不是静态或瞬态的字段都将被两种方法考虑@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;}生成的java代码如下:
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; }}该注解的使用方法和@toString的使用方法类似。
@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;}生成的java代码如下:
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块中,以确保在当前作用域的末尾调用清除方法。默认情况下@Cleanup假定释放资源的方法被命名为“close”,例如ByteArrayOutputStream的关闭流的方法为close,那么就无需指定释放资源的方法,但是如果ByteArrayOutputStream的关闭流的方法叫destroy,那么就需要进行指定了,指定的方式如下:@Cleanup("destroy")下面我们来验证下这个注解的功能,先覆写资源的释放方法:
public void testCleanup(){try {@Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream() { // 覆写释放资源方法@Overridepublic void close() throws IOException {super.close();System.out.println("I've been closed!");}};baos.write(new byte[] {'Y','e','s'});System.out.println(baos.toString());} catch (IOException e) {e.printStackTrace();}}测试结果如下:
YesI've been closed!通过上面的测试结果,可以得出,默认调用了close方法来释放资源。
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(); }}生成的java代码如下:
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
在一个实例方法的情况下,或者一个静态方法的类对象,synchronized关键字将锁定当前对象(this)public void testSynchronized() {Runnable runner = new Runnable() {public void run() {synchronized($lock) {System.out.println("Thread locked on $lock and sleeping for 5 seconds. You should see the date output after the wait.");try {Thread.sleep(5000);} catch (InterruptedException e) {}System.out.println("Done sleeping.");}}};new Thread(runner).start();// Make sure we don't outrun the new thread.try {Thread.sleep(500);} catch (InterruptedException e) {}Date today = new Date();System.out.println("Main thread attempting to lock on $lock.");System.out.println(synchronizedFormat(today));}private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");@Synchronized // 使用在方法上 public String synchronizedFormat(Date date) { return format.format(date); }// 上面的代码会生成如下的java代码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); }}该注解可能会造成一些线程问题,建议慎用!
@NoArgsConstructor and @AllArgsConstructor
@NoArgsConstructor注解用来生成无参的构造函数
@AllArgsConstructor注解用来生成带参的构造函数(注意:生成的带参构造函数是带有所有的属性)
@Log
目前支持的日志框架如下:
下面以slf4j为例来进行说明
1、pom文件添加依赖
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.1.2</version></dependency>2、在src/main/resources目录加入slf4j的配置文件
<?xml version="1.0" encoding="UTF-8"?> <configuration> <substitutionProperty name="logbase" value="${user.dir}/logs/ " /> <!-- 这个是要配置输出文件的 --> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern> </layout> </appender> <!-- 文件输出日志 (文件大小策略进行文件输出,超过指定大小对文件备份) --> <appender name="logfile" class="ch.qos.logback.core.rolling.RollingFileAppender"> <Encoding>UTF-8</Encoding> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <File>${logbase}%d{yyyy-MM-dd}.log.html</File> <FileNamePattern>${logbase}.%d{yyyy-MM-dd}.log.html.zip </FileNamePattern> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <MaxFileSize>2MB</MaxFileSize> </triggeringPolicy> <layout class="ch.qos.logback.classic.html.HTMLLayout"> <pattern>%date%level%thread%10logger%file%line%msg</pattern> </layout> </appender> <root> <level value="debug" /> <appender-ref ref="stdout" /> <appender-ref ref="logfile" /> </root> </configuration>3、测试类
package com.chhliu.lombok.lombokstart;import lombok.extern.slf4j.Slf4j;@Slf4jpublic class LogExampleOther {public static void main(String... args) {log.error("i'm the king of the world");}}测试结果如下:
2017-05-15 21:15:31,262 [main] ERROR com.chhliu.lombok.lombokstart.LogExampleOther - i'm the king of the world
从上面的示例中,可以发现,@Log的功能还是非常方便的。Lombok还提供了一个简易的日志浏览界面,效果如下:
@Builder
@Builderpublic class BuilderExampleBefore {private String name;private int age;}
测试类如下:
public class BuilderExampleBeforeTest {@Testpublic void test(){BuilderExampleBuilder builder = BuilderExample.builder().age(20).name("chhliu");// 链式api的方式System.out.println(builder.toString());}}从上面的示例中可以看到,我们使用了链式api来实现赋值,比构造方法一个个的set要好看许多吧!
总结
Lombok到目前为止,存在很多的争议,具体技术选型的时候,要看项目的侧重点!
官网地址如下:http://jnb.ociweb.com/jnb/jnbJan2010.html
- 使用Lombok简化java代码的编写
- 使用Lombok简化Java代码
- 使用 lombok 简化 Java 代码
- lombok使用,简化代码
- Lombok简化Java代码
- 使用Lombok简化你的代码
- lombok的使用,简化代码又省力
- Lombok简化Java代码的好工具
- Lombok - 简化java代码
- Lombok引入简化Java代码
- Lombok 简化java代码注解
- 小试Lombok,简化Java代码
- lombok 简化java代码注解 理解
- lombok 简化java代码注解 理解
- lombok 简化java代码注解 理解
- JAVA奇技淫巧简化代码之lombok
- 使用Lombok消除冗长的java代码
- 简化代码神器Lombok
- android超级新手须知
- 正向代理和反向代理
- 安装TensorFlow
- SQL中的内外连接、排序和求平均值的语句
- new与malloc的区别?
- 使用Lombok简化java代码的编写
- fastboot:刷系统中各个img文件
- Java 集合——ConcurrentHashMap
- 学习Web安全建议
- 快速理解盒模型
- flex实现div/li等水平居中布局
- Android系统编译脚本理解
- android librtmp 推送h264流 aac流 基本过程总结四 推流x264
- 跳转页面referrer验证失败