1. Introduction

Among many programming languages at present, Java language is still eye-catching. Whether it is enterprise-class server development or Android client development, It is the first choice for development language. Even in the field of big data development, Java language can also occupy a place, such as Hadoop, Spark, Flink big data, etc. In order to greatly improve the efficiency and simplicity of Java development, a Java library Lombok was born.

First, let’s look at Lombok’s official description:

Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java. Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.

Lombok, a Java library for editors and build tools, can enhance the Java code you write, such as not writing getters for entity classes, not writing equals methods, but automatically generating log output variables, and so on. Reduce duplicate template code. With an overview of the capabilities provided by the Lombok framework, let’s take a real look at the annotations provided by Lombok to see how they can help us improve the simplicity and efficiency of writing Java code.

The main contents of this paper are as follows:

  • Lombok plug-in installation
  • Lombok often uses annotations

Example project: github.com/wrcj12138aa…

  • Lombok – actions:

Environment support:

  • JDK 8
  • SpringBoot 2.1.4
  • Maven 3.6.0

2. The body

2.1 installation Lombok

To use Lombok, you need to install it in the IDE you’re using. Here’s an example of how to install IDEA:

  • Search for Lombok by going to File -> Settings -> Plugin -> Marketplace

  • Select the search result Lombok and click Install to Install.

  • Restart after the installation is complete.

Lombok based on Eclipse plug-in installation method here is not described in detail, the official also gives the corresponding documentation: projectlombok.org/setup/eclip…

With the Lombok plug-in installed in the IDE, we can add Lombok dependencies to the POM.xml file to use.

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
    <scope>provided</scope>
</dependency>
Copy the code

Note: The POM dependency is set to Scope provided so that Lombok libraries are not packaged into the program.

2.2 @ Getter / @ Setter

Normally we write an entity class to provide getters and setters for any number of fields, such as the example user.java class shown below

It is often the case that when an entity class adds or modifies a field, we need to handle the adjustment separately, which is cumbersome and repetitive. In this case, if we use Lombok to provide @getter / @setter annotations, it will save us the maintenance of Getter and Setter methods, The getters and setters are automatically generated by Lombok on the User class, and the final bytecode for both is the same, whereas the code we now write on user.java is only 7 lines:

@Getter
@Setter
public class User {
    private Integer id;
    private String username;
    private String password;
}
Copy the code

The test results are as follows:

public class UserTests {
    @Test
    public void test(a) {
        User user = new User();
        user.setUsername("one");
        user.setPassword("zxc123");
        Assert.assertEquals(user.getUsername(), "one");
        Assert.assertEquals(user.getPassword(), "zxc123"); }}Copy the code

The @getter / @setter annotation can be used not only on a class, but also on a field to indicate that Getter/ Setter methods are automatically generated for that field.

@Getter
@Setter
private String password;
Copy the code

The difference between using an annotation on a class versus a field is that if the annotation is used on a class, it is only valid for non-static fields of that class.

One thing to note is that if the @getter annotation decorates a variable of type Boolean, the generated Getter method signature is of the isXXX form, not the getXXX form.

In addition, @getter / @setter also provides the access control property lombox.accessLevel value(), which defaults to PUBLIC, while the other selected values are enumerated: MODULE, PROTECTED, PACKAGE, PRIVATE

2.3 @ NonNull

As the name implies, @nonNULL is used to mark a field or argument in a class that is not allowed to be null. Null pointer validation code is generated wherever the field is used. NullPointException (NPE) is thrown if the @nonNULL variable is NULL. For example, the following example code:

public class User {
    private Integer id;
    private String username;
    private String password;

    public User(Integer id, @NonNull String username, @NonNull String password) {
        this.id = id;
        this.username = username;
        this.password = password; }}Copy the code

Using the @nonnull annotation we can get the following bytecode information after decompilation, and this is the final code that Lombok generates for us:

public class User {
    private Integer id;
    private String username;
    private String password;

    public User(Integer id, @NonNull String username, @NonNull String password) {
        if (username == null) {
            throw new NullPointerException("username is marked non-null but is null");
        } else if (password == null) {
            throw new NullPointerException("password is marked non-null but is null");
        } else {
            this.id = id;
            this.username = username;
            this.password = password; }}}Copy the code

2.4 Constructor annotations

Let’s take a look at the common scenario of writing constructor methods for entity classes, Lombok provides three different constructor annotations @noargsConstructor / @AllargsConstructor / @requiredargsConstructor, each of which is described next.

  • @noargsConstructor generates a constructor method with no arguments for an entity class

  • @AllargsConstructor generates constructor methods for an entity class that take each argument in addition to static decorated fields.

  • @requiredargsConstructor generates constructor methods for entity classes that specify fields that need to be final or @nonNULL.

    ```java @RequiredArgsConstructor public class User3 { private Integer id; private final String username; @NonNull private String password; } ` ` `Copy the code

    User3 User3 = new User3(” User3 “, “zxc123”);

2.5 @ ToString

The @toString method automatically generates easy-to-read ToString methods for the class, with attribute names and values with non-static fields, making it easy to print for everyday development.

@Getter
@Setter
@AllArgsConstructor
@ToString
public class User2 {
    private Integer id;
    private String username;
    private String password;
}
Copy the code

Finally compiled into bytecode, decompiled results are as follows:

public class User2 {
    private Integer id;
    private String username;
    private String password;
    / / save the setter/getter
    public String toString(a) {
        return "User2(id=" + this.getId() + ", username=" + this.getUsername() + ", password=" + this.getPassword() + ")"; }}Copy the code

In addition, the @toString annotation also supports setting the logging output for specifying which fields are not required in the ToString method. Use the @tostring. Exclude attribute to Exclude fields that do not need to appear in the ToString. Use the @tostring. Include tag to Exclude fields that do not need to appear in the ToString.

@Getter
@Setter
@AllArgsConstructor
@ToString
public class User2 {
    @ToString.Exclude
    private Integer id;
    @ToString.Include
    private String username;
    @ToString.Include
    private String password;
}
Copy the code

The log effect of the User2 object is User2(username= User2, password=zcx123).

2.6 @ EqualsAndHashCode

The @EqualSandHashCode annotation is used to automatically override the equals and hashCode methods based on the non-static fields owned by the class, which we can use for comparison between objects. Similar to @toString and @equalSandHashCode, you can also use fields that need to be compared and exclude fields that do not need to be compared. See the following example:

@Getter
@Setter
@AllArgsConstructor
@ToString
@EqualsAndHashCode
public class User4 {
    @EqualsAndHashCode.Exclude
    private Integer id;
    @EqualsAndHashCode.Include
    private String username;
    @EqualsAndHashCode.Exclude
    private String password;
}
Copy the code

After writing the entity class code, let’s write the test method to test the effect:

@Test
public void testEqual(a) {
    User4 user4 = new User4(1."user4"."zxc");
    User4 user4_2 = new User4(1."user4"."123");
    Assert.assertEquals(user4, user4_2); // ture
}
Copy the code

2.7 @ Data / @ the Value

The @data / @value annotation provides a more comprehensive code generation capability, equivalent to the following annotations

@Getter
@Setter
@RequiredArgsConstructor
@ToString
@EqualsAndHashCode
Copy the code

Both annotations can only be used on classes, unlike @data, where @value is used to decorate immutable classes. If there are no specific restrictions on the general entity class, you can usually use the @data annotation directly.

2.8 @ Builder

Builder is a very powerful annotation that provides an API for building objects based on the Builder pattern. Use the @Builder annotation to automatically generate the Builder () method for our entity class, assign fields directly to the field name method, and finally use the build() method to build an entity object.

@Data
@Builder
public class User6 {
    private Integer id;
    private String username;
    private String password;
}

@Test
public void testBuilder(a) {
    User6 user6 = User6.builder().id(1).username("user6").password("zxc123").build();
    log.warn("testLog: {}", user6); // User6(id=1, username=user6, password=zxc123)
}
Copy the code

Note that @Builder does not support superclass field generation. When an entity class has a superclass, @Builder can only generate field construction methods for the current class. Lombok provides a new annotation @superBuilder to deal with situations where you need to use the field methods of a parent class. Here’s how the @SuperBuilder annotation can be used:

@SuperBuilder
@Getter
@Setter
public class Parent {
   private int id;
   private String name;
}

@SuperBuilder
@Data
public class Child extends Parent {
    private String childName;
}
Copy the code

Example call:

Child child = Child.builder().id(1).name("Superclass name").childName("Subclass name").build();
System.out.println(child.getId());
Copy the code

The Lombok Plugin has not yet been updated to support @superBuilder, so the builder() method cannot be found.

Also can refer to this way to deal with the situation of the inheritance: reinhard. Codes / 2015/09/16 /…

2.9 Log Annotations

Lombok also provides annotations to automatically generate Logger objects for elegant logging, just by using a logging annotation such as @log on the class. Of course Lombok supports several logging frameworks and provides the following annotations:

  • @commonslog equivalent effect: private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

  • @flogger Equivalent effect: private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass();

  • @ JBosLog equivalent effect: private static final org. Jboss. Logging. The Logger log = org. Jboss. Logging. The Logger. GetLogger (LogExample. Class);

  • @log equivalent effect: private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());

  • @ Log4j equivalent effect: private static final. Org. Apache Log4j. Logger log = org. Apache.. Log4j Logger. GetLogger (LogExample. Class);

  • @log4j2 equivalent effect: private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);

  • @ Slf4j equivalent effect: private static final org. Slf4j. The Logger log = org. Slf4j. LoggerFactory. GetLogger (LogExample. Class);

  • @xslf4j equivalent effect: private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

The following code uses the @slf4J annotation for logging output:

@Slf4j
public class UserTests {
    / /...
    @Test
    public void testLog(a) {
        User5 user5 = new User5();
        user5.setId(1);
        user5.setUsername("user5");
        user5.setPassword("zxc123");
        log.warn("testLog: {}", user5);
   / / 21:57:15. 488. [the main] WARN com one. Learn. Lombok. UserTests - testLog: User5 (id = 1, the username = User5, password = zxc123)}}Copy the code

2.10 @ the Cleanup

@ the Cleanup for marking need to release the cleaning operation resource object variables, such as a FileInputStream, FileOutputStream, tag after resource objects, after using can be automatically shut down and clean up, In fact, the Lombok implementation works the same way as the Java7 feature try with Resource, which allows us to block the template code for closing resources. Here is an example of using @cleanup:

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); }}}Copy the code

Decompilation of the bytecode generated by compiling Cleanupexample. Java yields the following results:

public class CleanupExample {
    / /...
    public static void main(String[] args) throws IOException {
        FileInputStream in = new FileInputStream(args[0]);
        try {
            FileOutputStream out = new FileOutputStream(args[1]);
            try {
                byte[] b = new byte[10000];
                while(true) {
                    int r = in.read(b);
                    if (r == -1) {
                        return;
                    }
                    out.write(b, 0, r); }}finally {
                if (Collections.singletonList(out).get(0) != null) { out.close(); }}}finally {
            if (Collections.singletonList(in).get(0) != null) { in.close(); }}}}Copy the code

2.11 @ SneakyThrows

@sneakyThrows () throws (); @sneakythrows () throws () throws ();

public class SneakyThrowsExample implements Runnable {
  @SneakyThrows(UnsupportedEncodingException.class)
  public String utf8ToString(byte[] bytes) {
    return new String(bytes, "UTF-8");
  }

  @SneakyThrows
  public void run(a) {
    throw newThrowable(); }}Copy the code

Finally compiled into bytecode, decompiled results are as follows:

public class SneakyThrowsExample implements Runnable {
    public SneakyThrowsExample(a) {}public String utf8ToString(byte[] bytes) {
        try {
            return new String(bytes, "UTF-8");
        } catch (UnsupportedEncodingException var3) {
            throwvar3; }}public void run(a) {
        try {
            throw new Throwable();
        } catch (Throwable var2) {
            throwvar2; }}}Copy the code

2.12 val/var

Val /var is used to modify local variables so that the type of the variable is automatically inferred from the expression to the right of the equal sign. This feature is borrowed from the automatic type inference feature of many programming languages. The difference between val and var is that val is used with immutable variables and var with mutable variables. When a variable decorated by val is reassigned, the compiler prompts Error: Java: Cannot assign a value to the final variable X. The actual usage is also relatively simple, refer to the following code:

@Slf4j
public class VarValExample {
    public static void main(String[] args) {
        val text = "abc";
        // text = "1"; // Error: Java: cannot assign value 'to final variable text.
        var num = 1;
        num = 2;
        log.info("text:{},num:{}", text, num); // text:abc,num:2}}Copy the code

3. The conclusion

At this point, we’ve learned about nearly 80% of Lombok’s commonly used annotations, and the application is more than enough for our daily development. Start using Lombok, and slowly start to feel the efficiency and elegance of the code.

If you feel that there is harvest after reading, welcome to the point [good], click on the article header diagram, scan the code to pay attention to [famous technology blog] ๐Ÿ˜„๐Ÿ˜„๐Ÿ˜„.

4. Reference

  • Project Lombok: projectlombok.org/

  • Stackabuse.com/project-lom…

  • Project Lombok: Reducing Java Boilerplate Code: stackabuse.com/project-lom…

  • Summary of Lombok commonly used the use of annotations: segmentfault.com/a/119000001…

  • Lombok @Builder with Inheritance: www.baeldung.com/lombok-buil…

  • Blog.didispace.com/java-lombok…

  • Lombok ‘s @ Builder annotation and inheritance: reinhard. Codes / 2015/09/16 /…

  • Lombok: Making JAVA code more elegant: blog.didispace.com/java-lombok…

  • Lombok: mp.weixin.qq.com/s?__biz=MzI…