This article continues the introduction to the general use of Lombok and focuses on Lombok’s use of annotations.
@Value
@Value is an immutable annotation in @data, all properties are private and final by default, and no setters methods are generated. Classes are also final by default. For example, @data generates toString(), equals() and hashCode() methods, gets a getter for each field, and generates a constructor that overwrites each argument (except for initializing the final segment in the field declaration).
For example,
@Value
public class ValueExample<T> {
String name;
@Wither(AccessLevel.PACKAGE)
@NonFinal
int age;
double score;
protected String[] tags;
}Copy the code
What it actually generates is
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.Override
public 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.Override
public 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.Override
public String toString() {
return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")"; }}Copy the code
In practice, @value is shorthand: Final @toString @equalSandHashCode @allargsconstructor @fieldDefaults (makeFinal = true) Level = accesslevel.private) @getter, in addition to explicitly including the implementation of any associated methods, only means that no warnings are issued.
For example, if you write a toString() method and nothing goes wrong, Lombok won’t regenerate it for you.
Furthermore, any explicit constructor, regardless of the argument list, means lombok does not generate constructors. If you want Lombok to generate all constructors, tag @allargsconstructor on your class. You can use @ lombok. Experimental. Tolerate any constructor or method, so that they hold in lombok.
You can override the default final and default private behavior using explicit access levels on fields or using @nonfinal or @Packageprivate annotations. @nonfinal can also be used on classes to remove the final keyword.
@Builder
The @Builder annotation generates a complex Builder API for your class.
@Builder allows you to automatically generate the code you need to make your classes instantiable using the following code:
Person.builder().name("Adam Savage")
.city("San Francisco").job("Mythbusters")
.job("Unchained Reaction").build();Copy the code
@Builder can be placed on a class, constructor, or method. While patterns are the most common use cases on classes and constructors, @Builder is the easiest to explain in terms of methods.
Tagging @Builder on a method follows these principles
-
A static inner class called FooBuilder that has the same type parameters as a static method (builder).
-
In Builder, each target parameter has a private non-static, non-final property
-
In Builder, a package-level private constructor with no arguments.
-
In the Builder, a setter method is similar to each parameter of the target, which has the same type and the same name as that parameter. It returns the builder itself so that setter calls can be linked, as shown in the example above.
-
In Builder, there is a build() method that calls the method and passes in each field. It returns the same type as the target.
-
In Builder, a reasonable implementation of toString()
-
In the class that contains the target, a Builder () method that creates a new instance of the constructor
@Builder has a lot of redundant code. Take a look at this example
@Builder
public class BuilderExample {
private Long id;
private String name;
private Integer age;
}Copy the code
It is equivalent to the following code
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 + ")"; }}}Copy the code
There is a problem, however. @Builder does not generate the no-argument constructor for you. The no-argument constructor is needed and is usually used for deserialization purposes, so @allargsconstructor and @noargsconstructor must be added
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
}Copy the code
@Singular
Singular is often used with Builder, and Lombok treats the Builder as a collection by annotating one of its parameters (if using an @Builder annotated method or constructor) or fields (if using an @Builder annotated class) with @Singular annotation, And it generates two Add methods instead of setter methods. One of these methods adds a single element to a Collection and all the elements of another Collection to the Collection.
For example, the following uses @singular code
public class SingularExample {
private Long id;
private String name;
private Integer age;
@Singular
private Set<String> Girlfriends;
}Copy the code
It looks like this code
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;
}Copy the code
@Synchronized
@synchronized is a safe variant of the Synchronized modifier. Like synchronized, this annotation can only be used with static and instance methods. It operates like the synchronized keyword, but it locks to a different object. If you place this annotation on a private property, it will automatically lock the $lock object for you, if it doesn’t, it will automatically create it for you. If you place this annotation on a static method, it will automatically LOCK the $LOCK object for you.
You can create your own locks, if you have already created the $lock and $lock fields themselves, then of course they will not be generated. You can also choose to lock other fields by specifying them as arguments to the @synchronized annotation. In this variant of usage, fields are not automatically created; you must explicitly create them yourself, or an error will be thrown.
Locking this or your own class object has other effects because other code outside your control can also lock these objects, which can lead to race conditions and other threading errors.
Here is an example
import lombok.Synchronized; public class SynchronizedExample { private final ObjectreadLock = new Object(); @Synchronized public static void hello() { System.out.println("world"); } @Synchronized public int answerToLife() { return 42; } @Synchronized("readLock") public void foo() { System.out.println("bar"); }}Copy the code
It is equivalent to the following
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"); }}}Copy the code
@Cleanup
You can use the @cleanup annotation to automatically Cleanup a given resource before a block of code is finished executing. You can do this by annotating any local variable declarations with the @cleanup annotation, like this:
@Cleanup InputStream in= new FileInputStream (" some/file ");Copy the code
It automatically executes the in.close() method at the end of a block of code, and Lombok ensures that this method is executed when a try… Finally… Within the block
If the type of object you want to clean does not have a close() method, but some other no-argument method, you can specify the name of this method, as follows:
@Cleanup("dispose") org.eclipse.swt.widgets.CoolBar bar = new CoolBar(parent, 0);Copy the code
By default, the cleanup method is assumed to be close(). Cleanup methods with 1 or more arguments cannot be called with @cleanup. Here is an example
import lombok.Cleanup; import java.io.*; public class CleanupExample { public static void main(String[] args) throws IOException { @Cleanup InputStreamin = 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); }}}Copy the code
This is equivalent to the following
import java.io.*; public class CleanupExample { public static void main(String[] args) throws IOException { InputStreamin = 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(); }}}}Copy the code
@Getter(lazy=true)
You can tell Lombok to generate a getter that evaluates the value once, the first time the getter is called, and caches it. This is useful if calculating the value takes up a lot of CPU, or if the value takes up a lot of memory.
To use this feature, create a private final variable and annotate it with the @getter (lazy = true) annotation. A cached cache is thread-safe, so you don’t have to worry. Here’s an example
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; }}Copy the code
It is equivalent to the following example
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; }}Copy the code
@Log
You put the @log variant on your class (whichever is appropriate for the logging system you use). You then have a static final log field, initialized with the name of your class, which you can then use to write logging statements.
Here are the different log options:
Here is an example
import lombok.extern.apachecommons.CommonsLog; import lombok.extern.java.Log; import lombok.extern.slf4j.Slf4j; @Logpublic class LogExample { public static void main(String[] args) { log.severe("Something's wrong here"); }}@Slf4jclass 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"); }}Copy the code
This is equivalent to the following example
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"); }}Copy the code
The var and val
Can represent any type!
Var can be used to represent variables, similar to let in other languages
Val can be used to represent a constant (final), similar to const in other languages
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); }Copy the code
Is equivalent to
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);
}Copy the code
Related links:
https://www.hellojava.com/a/74973.html
https://www.projectlombok.org/features/all
Recommended reading (Click to skip to reading)
1. SpringBoot content aggregation
2. Assemble interview questions
3. Design pattern content aggregation
4. Mybatis content aggregation
5. Multi-threaded content aggregation
See here, focus on one?