Section 13: simplify your code with Lombok

Posted by slushpuppie on Sat, 19 Feb 2022 17:11:18 +0100

[TOC]

In the development process, a large number of JavaBean s are usually defined, and then the constructor, getter, setter, equals, hashcode and toString methods of their properties are generated through the IDE. When adding properties or changing a property, such as naming and type, these methods mentioned above need to be regenerated. Such repetitive work is meaningless. The annotations in Lombok can easily solve these problems.

The principle of lombok implementation: mainly through the abstract syntax tree (AST), after compilation and processing, it corresponds to the class with its annotation, then the annotation compiler will automatically correspond to the annotation in the project, correspond to the annotation file in the lombok syntax tree, and automatically compile the correspondence to generate the getter or setter method in the corresponding class, so as to simplify the code

pom.xml add lombok

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>

@Getter @Setter annotation

This pair of annotations is well understood from the name. When used in front of member variables, it is equivalent to generating corresponding get and set methods for member variables. At the same time, it can also specify access modifiers for the generated methods. Of course, it defaults to public. Let's take a direct look at the following simple examples:

// Rumenz.java
/**
 * @className: Rumenz
 * @description: TODO Class description
 * @author: Entry station rumenz com
 * @date: 2021/12/9
 **/
public class RumenzGetSet {
    @Getter @Setter
    private Integer id;
    @Getter @Setter
    private String name;

}
  • Equivalent to

    public class RumenzGetSet {
      private Integer id;
      private String name;
    
      public Integer getId() {
          return id;
      }
    
      public void setId(Integer id) {
          this.id = id;
      }
    
      public String getName() {
          return name;
      }
    
      public void setName(String name) {
          this.name = name;
      }
    }
    
@RestController
@RequestMapping("/rumenz")
public class RumenzController {

    @GetMapping("/index")
    public String index(){
        RumenzGetSet r=new RumenzGetSet();
        r.setId(1);
        r.setName("Entry station");

        return r.getId()+r.getName();
    }
}

visit http://127.0.0.1:8080/rumenz/index Return to 1 entry station

@NonNull annotation

This annotation can be used in front of the parameters of member methods or constructor methods. It will automatically generate a non null check on this parameter. If the parameter is null, a null pointer exception will be thrown. Take an example

public class RumenzNonNull {
    @Getter @Setter @NonNull
    private Integer id;
    @Getter @Setter @NonNull
    private String name;
}
  • Equivalent to

    public class RumenzNonNull {
      private Integer id;
      private String name;
    
      public Integer getId() {
          return id;
      }
    
      public void setId(Integer id) {
          if (id == null) throw new java.lang.NullPointerException("id");
          this.id = id;
      }
    
      public String getName() {
          return name;
      }
    
      public void setName(String name) {
          if (name == null) throw new java.lang.NullPointerException("name");
          this.name = name;
      }
    }
@GetMapping("/index1")
public String index1(){
    RumenzNonNull r=new RumenzNonNull();
    r.setId(1);
    r.setName(null);

    return r.getId()+r.getName();
}

visit http://127.0.0.1:8080/rumenz/index1 Error Java lang.NullPointerException: name is marked non-null but is null

@ToString

@ToString
public class RumenzToString {

    @Getter @Setter
    private Integer id;

    @Getter @Setter
    private String name;

    @Override
    public String toString() {
        return "RumenzToString{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
  • Equivalent to
public class RumenzToString {

    private Integer id;

    private String name;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "RumenzToString{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
@GetMapping("/index2")
public String index2(){
     RumenzToString r=new RumenzToString();
     r.setId(1);
     r.setName("Entry station");
     return r.toString();
}

visit http://127.0.0.1:8080/rumenz/index1 Return RumenzToString{id=1, name = 'entry station'}

EqualsAndHashCode annotation

@EqualsAndHashCode
public class RumenzEqualsAndHashCode {

    @Getter @Setter
    private Integer id;
    @Getter @Setter
    private String name;

}
  • Equivalent to

    public class RumenzEqualsAndHashCode {
      private Integer id;
      private String name;
    
      public Integer getId() {
          return id;
      }
    
      public void setId(Integer id) {
          this.id = id;
      }
    
      public String getName() {
          return name;
      }
    
      public void setName(String name) {
          this.name = name;
      }
    
      @Override
      public boolean equals(Object o) {
          if (this == o) return true;
          if (!(o instanceof RumenzEqualsAndHashCode)) return false;
          RumenzEqualsAndHashCode that = (RumenzEqualsAndHashCode) o;
          return id.equals(that.id) &&
                  name.equals(that.name);
      }
    
    }
@GetMapping("/index3")
public String index3(){
    RumenzEqualsAndHashCode r1=new RumenzEqualsAndHashCode();
    r1.setId(1);
    r1.setName("Entry station");

    RumenzEqualsAndHashCode r2=new RumenzEqualsAndHashCode();
    r2.setId(1);
    r2.setName("Entry station");
    if(r1.equals(r2)){
    return "equal";
    }
    return "Unequal";
}

@Data annotation

  • 1) Generating parameterless construction method;
  • 2) set/get method of property;
  • 3) equals(), hashCode(), toString(), canEqual() method.
@Data(staticConstructor="of")
public class RumenzData {


    private Integer id;

    private String name;

}
//Equivalent to

public class RumenzData {
    private Integer id;
    private String name;

    private RumenzData() {
    }

    public static RumenzData of() {
        return new RumenzData();
    }

    public Integer getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public void setId(final Integer id) {
        this.id = id;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof RumenzData)) {
            return false;
        } else {
            RumenzData other = (RumenzData)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$id = this.getId();
                Object other$id = other.getId();
                if (this$id == null) {
                    if (other$id != null) {
                        return false;
                    }
                } else if (!this$id.equals(other$id)) {
                    return false;
                }

                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(final Object other) {
        return other instanceof RumenzData;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $id = this.getId();
        int result = result * 59 + ($id == null ? 43 : $id.hashCode());
        Object $name = this.getName();
        result = result * 59 + ($name == null ? 43 : $name.hashCode());
        return result;
    }

    public String toString() {
        return "RumenzData(id=" + this.getId() + ", name=" + this.getName() + ")";
    }
}
@GetMapping("/index4")
public String index4(){
   RumenzData of = RumenzData.of();
   of.setName("Entry station");
   String name = of.getName();
   return name;
}

@Cleanup annotation

This annotation is used in front of the variable to ensure that the resource represented by this variable will be automatically closed. By default, it calls the close() method of the resource. If the resource has other closing methods, you can use @ Cleanup("methodName") to specify the method to be called. Take the input / output stream as an example:

@GetMapping("/index5")
public String index5() throws IOException {

   File file = ResourceUtils.getFile("classpath:application.properties");
   @Cleanup  InputStream inputStream = new FileInputStream(file);

   byte b[]=new byte[(int) file.length()];
   inputStream.read(b);
   //@Cleanup replaces InputStream close();
   return new String(b);
}

Equivalent to

@GetMapping({"/index5"})
public String index5() throws IOException {
        File file = ResourceUtils.getFile("classpath:application.properties");
        FileInputStream inputStream = new FileInputStream(file);

        String var4;
        try {
            byte[] b = new byte[(int)file.length()];
            inputStream.read(b);
            var4 = new String(b);
        } finally {
            if (Collections.singletonList(inputStream).get(0) != null) {
                inputStream.close();
            }

        }

        return var4;
}

@NoArgsConstructor annotation

@NoArgsConstructor is used on classes and can provide a parameterless constructor

@NoArgsConstructor
public class RumenzNoArgsConstructor {
    private Integer id;
    private String name;
}

Equivalent to

public class RumenzNoArgsConstructor {
    private Integer id;
    private String name;

    public RumenzNoArgsConstructor() {
    }
}

@RequiredArgsConstructor annotation

Specify the property generation construction method of final

@ToString
@RequiredArgsConstructor
public class RumenzRequiredArgsConstructor {
    private Integer id;
    private final String name;
}

//Equivalent to

public class RumenzRequiredArgsConstructor {
    private Integer id;
    private final String name; //final

    public String toString() {
        return "RumenzRequiredArgsConstructor(id=" + this.id + ", name=" + this.name + ")";
    }

    public RumenzRequiredArgsConstructor(final String name) {
        this.name = name;
    }
}

@AllArgsConstructor annotation

All fields in the class generate a constructor with parameters

@ToString
@AllArgsConstructor
public class RumenzAllArgsConstructor {
    private  Integer id;
    private  String name;
}

//Equivalent to

public class RumenzAllArgsConstructor {
    private Integer id;
    private String name;

    public String toString() {
        return "RumenzAllArgsConstructor(id=" + this.id + ", name=" + this.name + ")";
    }

    public RumenzAllArgsConstructor(final Integer id, final String name) {
        this.id = id;
        this.name = name;
    }
}

@Value annotation

  • 1) Parametric construction method;
  • 2) If you only add @ Value annotation without other restrictions, the class properties will be compiled into final, so there is only get method, not set method.
@ToString
@Value
public class RumenzValue {
    private Integer id;
    private String name;
}

//Equivalent to

public final class RumenzValue {
    private final Integer id;
    private final String name;

    public RumenzValue(final Integer id, final String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof RumenzValue)) {
            return false;
        } else {
            RumenzValue other = (RumenzValue)o;
            Object this$id = this.getId();
            Object other$id = other.getId();
            if (this$id == null) {
                if (other$id != null) {
                    return false;
                }
            } else if (!this$id.equals(other$id)) {
                return false;
            }

            Object this$name = this.getName();
            Object other$name = other.getName();
            if (this$name == null) {
                if (other$name != null) {
                    return false;
                }
            } else if (!this$name.equals(other$name)) {
                return false;
            }

            return true;
        }
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $id = this.getId();
        int result = result * 59 + ($id == null ? 43 : $id.hashCode());
        Object $name = this.getName();
        result = result * 59 + ($name == null ? 43 : $name.hashCode());
        return result;
    }

    public String toString() {
        return "RumenzValue(id=" + this.getId() + ", name=" + this.getName() + ")";
    }
}

@Sneakythlows annotation

This annotation is used for methods. You can wrap the code in the method with try catch statements, catch exceptions, and use Lombok. In catch Snapythlow (E) throws an exception. You can specify which exception to throw in the form of @ sneakythlows (exception. Class). A very simple annotation. Take a direct look at an example:

@SneakyThrows
@GetMapping("/index9")
public String index9() {

        //Using @ SneakyThrows eliminates the need to throw an exception explicitly
        File file = ResourceUtils.getFile("classpath:application.properties");
        @Cleanup  InputStream inputStream = new FileInputStream(file);

        byte b[]=new byte[(int) file.length()];
        inputStream.read(b);
        //@Cleanup replaces InputStream close();
        return new String(b);
}

//Equivalent to

@GetMapping({"/index9"})
public String index9() {
        try {
            File file = ResourceUtils.getFile("classpath:application.properties");
            FileInputStream inputStream = new FileInputStream(file);

            String var4;
            try {
                byte[] b = new byte[(int)file.length()];
                inputStream.read(b);
                var4 = new String(b);
            } finally {
                if (Collections.singletonList(inputStream).get(0) != null) {
                    inputStream.close();
                }

            }

            return var4;
        } catch (Throwable var9) {
            throw var9;
        }
}

@Synchronized annotation

Synchronized is an important keyword in thread safety. It is a kind of synchronization lock, which is mainly used to ensure that only one thread can execute a method or a piece of code at the same time. Generally, synchronized is used to lock code blocks instead of methods, because locking code blocks is more efficient.

public class RumenzSynchronized {

    private final Object readLock = new Object();

    @Synchronized
    public static void hello() {
        System.out.println("rumenz.com");
    }

    @Synchronized
    public int answerToLife() {
        return 110;
    }

    @Synchronized("readLock")
    public void foo() {
        System.out.println("Entry station");
    }
}

//Equivalent to

public class RumenzSynchronized {
    private static final Object $LOCK = new Object[0];
    private final Object $lock = new Object[0];
    private final Object readLock = new Object();

    public RumenzSynchronized() {
    }

    public static void hello() {
        synchronized($LOCK) {
            System.out.println("rumenz.com");
        }
    }

    public int answerToLife() {
        synchronized(this.$lock) {
            return 110;
        }
    }

    public void foo() {
        synchronized(this.readLock) {
            System.out.println("Entry station");
        }
    }
}

@Builder annotation

It is used in classes, constructors and methods to provide you with complex builder APIs

@ToString
@Builder
public class RumenzBuilder {
    private Integer id;
    private String name;
}

//Equivalent to

public class RumenzBuilder {
    private Integer id;
    private String name;

    RumenzBuilder(final Integer id, final String name) {
        this.id = id;
        this.name = name;
    }

    public static RumenzBuilder.RumenzBuilderBuilder builder() {
        return new RumenzBuilder.RumenzBuilderBuilder();
    }

    public String toString() {
        return "RumenzBuilder(id=" + this.id + ", name=" + this.name + ")";
    }

    public static class RumenzBuilderBuilder {
        private Integer id;
        private String name;

        RumenzBuilderBuilder() {
        }

        public RumenzBuilder.RumenzBuilderBuilder id(final Integer id) {
            this.id = id;
            return this;
        }

        public RumenzBuilder.RumenzBuilderBuilder name(final String name) {
            this.name = name;
            return this;
        }

        public RumenzBuilder build() {
            return new RumenzBuilder(this.id, this.name);
        }

        public String toString() {
            return "RumenzBuilder.RumenzBuilderBuilder(id=" + this.id + ", name=" + this.name + ")";
        }
    }
}
@GetMapping("/index11")
public String index11() {
    RumenzBuilder rb=RumenzBuilder.builder().id(1).name("Entry station").build();
    return rb.toString();
}

@SuperBuilder

When the entity class has integration relationship, you need to use @ SuperBuilder, otherwise it will be called The builder will report an error

@Builder does not support the construction of parent class member properties. The @ SuperBuilder annotation is used to solve this problem.

When using @ Builder or @ SuperBuilder annotation, the null parameter constructor will not be created by default. If you have additional requirements for using null parameter constructor or all parameter constructor, you need to add the following annotation to both the subclass and the parent class:

Source code address of this summary:

introduce

  • Follow the [entry station] and reply to [1001] to get the quick reference manual of common linux commands
  • Follow the [entry station] reply [1003] to get the solution of LeetCode [java language implementation]
  • Pay attention to [entry station] and reply to [1004] to get the summary of Java basic core
  • Follow [entry site] and reply to [1009] to obtain Alibaba Java development manual

Topics: Java Spring Boot