本篇来接续上一篇文章 Lombok 常规使用介绍,主要介绍一下 Lombok 非常用注解。

@Value

@Value 是 @Data 中不可变的注解,所有的属性默认都是 private 和 final 的,并且不会生成 setters 方法。默认情况下,类也是 final 的。像是 @Data ,会生成 toString() ,也会生成 equals() 和 hashCode() 方法,每个字段都会获得一个 getter 方法,并且还会生成一个覆盖每个参数的构造函数(在字段声明中初始化final 段除外)。

例如

@Value
public class ValueExample<T> {String name;@Wither(AccessLevel.PACKAGE)@NonFinalint age;double score;protected String[] tags;}

它其实生成的是

public final class ValueExample {private final String name;private int age;private final double score;protected final String[] tags;@java.beans.ConstructorProperties({"name", "age", "score", "tags"})public ValueExample(String name, int age, double score, String[] tags) {this.name = name;this.age = age;this.score = score;this.tags = tags;}public String getName() {return this.name;}public int getAge() {return this.age;}public double getScore() {return this.score;}public String[] getTags() {return this.tags;}@java.lang.Overridepublic boolean equals(Object o) {if (o == this) return true;if (!(o instanceof ValueExample)) return false;final ValueExample other = (ValueExample)o;final Object this$name = this.getName();final Object other$name = other.getName();if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;if (this.getAge() != other.getAge()) return false;if (Double.compare(this.getScore(), other.getScore()) != 0) return false;if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;return true;}@java.lang.Overridepublic int hashCode() {final int PRIME = 59;int result = 1;final Object $name = this.getName();result = result * PRIME + ($name == null ? 43 : $name.hashCode());result = result * PRIME + this.getAge();final long $score = Double.doubleToLongBits(this.getScore());result = result * PRIME + (int)($score >>> 32 ^ $score);result = result * PRIME + Arrays.deepHashCode(this.getTags());return result;}@java.lang.Overridepublic String toString() {return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")";}
}

在实际使用过程中,@ Value是简写:final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true,level = AccessLevel.PRIVATE)@Getter,除了明确包括任何相关方法的实现外,只意味着不会发出警告。

例如,如果你编写了一个 toString() 方法,没有出现错误的话,那么 lombok 是不会为你再生成 toString() 方法的。

此外,任何显式构造函数,无论参数列表,都意味着lombok不会生成构造函数。如果你想让lombok生成所有的构造函数,请将 @AllArgsConstructor 标记在类上。你可以使用@ lombok.experimental.Tolerate标记任何构造函数或方法,以便将他们容纳在 lombok 中。

可以使用字段上的显式访问级别或使用 @NonFinal 或 @PackagePrivate 注解来覆盖默认的最终和默认的私有行为。@NonFinal 也可以在类上使用用来移除 final 关键字。

@Builder

@Builder注解为你的类生成复杂的构建器API。

@Builder 允许你使用以下代码自动生成使您的类可实例化所需的代码:

Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();

@Builder 可以被放在类、构造函数或者方法上。虽然 在类上 和 在构造函数上 模式是最常见的用例,但@Builder最容易用 方法 来解释。

在方法上标注 @Builder 遵循以下原则

  • 一个名为FooBuilder 的静态内部类,与静态方法(构建器)具有相同的类型参数。
  • 在 Builder 中,每个目标参数都有一个私有的非静态 、非 final 属性
  • 在 Builder 中,一个包级私有无参数的构造函数。
  • 在 Builder 中,与目标的每个参数类似的 setter方法,它与该参数具有相同的类型和相同的名称。 它返回构建器本身,以便可以链接setter调用,如上例所示。
  • 在 Builder 中,有一个 build()方法,它调用方法并传入每个字段。 它返回与目标相同的类型。
  • 在 Builder 中,一个合理的 toString() 实现
  • 在包含目标的类中,一个 builder() 方法,它创建构造器的新实例

@Builder 有很多冗余的代码,来看下面这个例子

@Builder
public class BuilderExample {private Long id;private String name;private Integer age;}

它就相当于是下面这段代码

public class User {private Long id;private String name;private Integer age;User(Long id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}public static User.UserBuilder builder() {return new User.UserBuilder();}public static class UserBuilder {private Long id;private String name;private Integer age;UserBuilder() {}public User.UserBuilder id(Long id) {this.id = id;return this;}public User.UserBuilder name(String name) {this.name = name;return this;}public User.UserBuilder age(Integer age) {this.age = age;return this;}public User build() {return new User(this.id, this.name, this.age);}public String toString() {return "User.UserBuilder(id=" + this.id + ", name=" + this.name + ", age=" + this.age + ")";}}
}

但是这里面有一个问题,@Builder 不会为你生成无参构造函数,无参构造函数是很需要的,一般常常在反序列化的时候使用,所以必须要加上 @AllArgsConstructor@NoArgsConstructor

@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {private Long id;private String name;private Integer age;
}

@Singular

Singular 常常与 Builder 一起使用,通过使用 @Singular注解注释其中一个参数(如果使用@Builder注释方法或构造函数)或字段(如果使用@Builder注释类),lombok会将该构建器视为集合,并且会生成两个 add 方法而不是 setter 方法。其中一个方法会为Collection 增加单个元素,以及将另一个集合的所有元素添加到集合中。

例如下面这段使用了 @Singular 的代码

public class SingularExample {private Long id;private String name;private Integer age;@Singularprivate Set<String> Girlfriends;
}

它就如同下面这段代码一样

public User.UserBuilder Girlfriend(String Girlfriend) {if (this.Girlfriends == null) {this.Girlfriends = new ArrayList();}this.Girlfriends.add(Girlfriend);return this;}public User.UserBuilder Girlfriends(Collection<? extends String> Girlfriends) {if (this.Girlfriends == null) {this.Girlfriends = new ArrayList();}this.Girlfriends.addAll(Girlfriends);return this;
}public User.UserBuilder clearGirlfriends() {if (this.Girlfriends != null) {this.Girlfriends.clear();}return this;
}

@Synchronized

@Synchronized 是 synchronized 修饰方法的一个安全的变体。就像 synchronized,这个注解仅仅能够用在静态和实例方法上。它的操作类似于 synchronized 关键字,但它锁定在不同的对象上。如果你把此注解放在了一个私有属性上面,它会为你自动锁定 $lock 对象,如果没有这个属性,它将为你自动创建。如果你把此注解放在了静态方法上面,它将为你自动锁定 $LOCK对象。

你可以创建自己的锁,如果你已经自己创建了$ lock$ LOCK字段,那么它们当然不会生成。你还可以选择锁住其他字段,方法是将其指定为@Synchronized注解的参数,在此用法的变体中,不会自动创建字段,你必须自己显式创建它们,否则将会抛出错误。

锁定这个或你自己的类对象会产生其他影响,因为不受你控制的其他代码也可以锁定这些对象,这可能会导致竞争条件和其他线程错误。

下面是一个示例

import lombok.Synchronized;public class SynchronizedExample {private final Object readLock = new Object();@Synchronizedpublic static void hello() {System.out.println("world");}@Synchronizedpublic int answerToLife() {return 42;}@Synchronized("readLock")public void foo() {System.out.println("bar");}
}

它就相当于如下

public class SynchronizedExample {private static final Object $LOCK = new Object[0];private final Object $lock = new Object[0];private final Object readLock = new Object();public static void hello() {synchronized($LOCK) {System.out.println("world");}}public int answerToLife() {synchronized($lock) {return 42;}}public void foo() {synchronized(readLock) {System.out.println("bar");}}
}

@Cleanup

你可以使用 @Cleanup 注解在代码块执行完之前自动清理给定的资源。你可以通过使用@Cleanup注解来注释任何局部变量声明来执行此操作,如下所示:

@Cleanup InputStream in = new FileInputStream(“some / file”);

它会在代码块的结尾处自动执行 in.close()方法,lombok 能确保此方法在try…finally…块内执行

如果你要清理的对象类型没有 close() 方法,而是其他一些无参数方法,则可以指定此方法的名称,如下所示:

@Cleanup("dispose") org.eclipse.swt.widgets.CoolBar bar = new CoolBar(parent, 0);

默认情况下,清除方法假定为close()。不能通过@Cleanup调用带有1个或多个参数的清理方法。下面是一个示例

import lombok.Cleanup;import java.io.*;public class CleanupExample {public static void main(String[] args) throws IOException {@Cleanup InputStream in = new FileInputStream(args[0]);@Cleanup OutputStream out = new FileOutputStream(args[1]);byte[] b = new byte[10000];while (true) {int r = in.read(b);if (r == -1) break;out.write(b, 0, r);}}
}

就相当于是如下

import java.io.*;public class CleanupExample {public static void main(String[] args) throws IOException {InputStream in = new FileInputStream(args[0]);try {OutputStream out = new FileOutputStream(args[1]);try {byte[] b = new byte[10000];while (true) {int r = in.read(b);if (r == -1) break;out.write(b, 0, r);}} finally {if (out != null) {out.close();}}} finally {if (in != null) {in.close();}}}
}

@Getter(lazy=true)

你可以让lombok生成一个getter,它将计算一次值,这是第一次调用这个getter,并把它缓存起来。如果计算该值占用大量CPU,或者该值占用大量内存,则此功能非常有用。

要使用此功能,请创建一个私有final变量,并使用@Getter(lazy = true)注解进行标注。缓存起来的 cache 是线程安全的,你无需担心,下面是一个例子

import lombok.Getter;public class GetterLazyExample {@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;}
}

它就相当于如下示例

public class GetterLazyExample {private final java.util.concurrent.AtomicReference<java.lang.Object> cached = new java.util.concurrent.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;}
}

@Log

你把 @Log 的变体放在你的类上(无论哪一个适用于你使用的日志系统)。然后,你有一个静态的最终日志字段,初始化为你的类的名称,然后你可以使用它来编写日志语句。

下面是不同的日志选择:

下面是一个示例

import lombok.extern.apachecommons.CommonsLog;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;@Log
public class LogExample {public static void main(String[] args) {log.severe("Something's wrong here");}
}@Slf4j
class LogExampleOther {public static void main(String... args) {log.error("Something else is wrong here");}
}@CommonsLog(topic="CounterLog")
class LogExampleCategory {public static void main(String... args) {log.error("Calling the 'CounterLog' with a message");}
}

就相当于如下示例

public class LogExample {private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());public static void main(String... args) {log.severe("Something's wrong here");}
}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");}
}public class LogExampleCategory {private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog");public static void main(String... args) {log.error("Calling the 'CounterLog' with a message");}
}

var 和 val

可以表示任何类型!

var 可以用来表示变量,类似其他语言中的 let

val 可以用来表示常量(final),类似其他语言中的 const

var str = "hello world";
val list = Arrays.asList(1,2,3,4);
System.out.println(str);
for(val item : list){System.out.printf("%dt",item);
}

等价于

String str = "hello world";
final List<Integer> list = Arrays.asList(1,2,3,4);
System.out.println(str);
for(final Integer item : list){System.out.printf("%dt",item);
}

相关链接:

https://www.hellojava.com/a/74973.htmlhttps://www.projectlombok.org/features/all

使用this调用已有的有参构造函数_加倍提升开发效率,继续深挖一下Lombok的使用相关推荐

  1. 使用this调用已有的有参构造函数_JavaScript 中的 this 的几种使用场景

    Javascript 中的 this,是一个高频变量,在很多场景下都会使用,所以总结了一下关于this指向的问题. 如未标明,以下内容是在非严格模式下生效 在函数中 this 到底取何值,是在函数真正 ...

  2. java子类要调用父类的无参构造函数

    如果子类要调用父类的无参构造函数,则通过super()调用来实现. 子类的每一个构造方法都必须显式或隐式调用父类的一个构造方法. 如果不显式调用, 则系统隐式调用super(),即父类的无参构造方法( ...

  3. pojo 带参构造函数_带有Java Pojo作为输入输出示例的AWS Lambda函数

    pojo 带参构造函数 在上一个教程中,我们看到了如何使用Java创建AWS Lambda函数,我们传递了String作为输入,还返回了String作为Output.如果您是第一次创建lambda函数 ...

  4. c++的构造函数极其调用(无参构造函数,有参构造函数,拷贝构造函数)

    1.c++编译器会自动调用构造函数 //构造函数(与类名相同) //析构函数:没有参数也没有任何返回类型,被自动调用 #include<iostream> using namespace ...

  5. 为什么要写无参构造函数

    今天在码代码时报错: Cannot construct instance of org.tech.arthur.model.domain.DataTestDTO (no Creators, like ...

  6. C++关于默认构造函数和无参构造函数

    C++关于默认构造函数和无参构造函数 默认构造函数 在不提供任何构造函数的情况下,编译器给出一个不带参数的,不包含代码的构造函数. #include<iostream> using nam ...

  7. 构造函数_析构函数_深拷贝与浅拷贝

    拷贝构造函数为什么要使用引用而不是值传递??? CExample aaa(2); CExample bbb(3); assignment operator                // bbb  ...

  8. C++ explicit禁止单参构造函数隐式调用

    1.单参数构造函数隐式调用 C++中单参数构造函数是可以被隐式调用的,主要有两种情形会隐式调用单参数构造函数: (1)同类型对象的拷贝构造:即用相同类型的其它对象来初始化当前对象. (2)不同类型对象 ...

  9. 为什么super()和this()调用语句不能同时在一个构造函数中出现的解释

    我想这应该是Java构造函数的一种机制吧,首先以子类和父类为例. 当你创建一个子类的实例时,首先会调用父类的构造函数,然后再调用子类的构造函数,如果父类中没有缺省构造函数,则必须再子类的构造函数中显示 ...

最新文章

  1. iOS 之 事件响应者链
  2. CentOS 7 学习(一) 配置LAMP和Nginx
  3. OpenCV在VS2005下的配置
  4. UIbutton系统按键(System)和图片按键(Custom)对比
  5. AngularStrap -- Popovers
  6. P2575 高手过招
  7. linux历史性能数据,Linux平台下如何看OS历史的性能数据
  8. java变量数据类型_java变量与数据类型
  9. 服务器重装系统要注意什么_视频海外服务器前期要准备什么?
  10. sqlmap工具使用用法详解
  11. html表格两种颜色,html – 表格细胞两个颜色背景对角线
  12. Js获取处理日期时间
  13. 阅读 深入理解JVM虚拟机笔记一
  14. android高效模拟器,51模拟器
  15. Ubuntu 安装 Libmodbus
  16. 用arcgis批量裁剪栅格(tiff)数据的矩形区域
  17. 华为联运游戏或应用审核驳回:检查HMS Core更新失败
  18. 计算机中心冷风通道,数据中心机房散热冷通道热通道问题分析
  19. deepin系统维护(系统扩容)deepin live
  20. HbuilderX表格练习2

热门文章

  1. numpy.max(a, axis=1) np.max(a, axis=1) 中的axis=1是那个维数?怎么理解?
  2. CenturyLink将在新加坡设立安全运营中心
  3. 【IMRaD】如何“科学地”写一篇科学研究论文
  4. 跳动的“loading”,个个都很惊艳
  5. CNI系列(三)插件实现
  6. php文本书写格式,在PHP中读/写MS Word文件
  7. 二本大一新生拒绝摆烂,2个月后的觉醒
  8. 【陈工笔记】# 同步网络和异步网络的理解 #
  9. 23种设计模式 - C++实现
  10. 重装系统大师计算机硬件不兼容,电脑重装系统能解决哪些问题?电脑重装系统后常见问题解决方法...