Every Java kid should know about Lombok

Lombok relies heavily on compile-time code generation to help you automatically generate common Java code based on templates, such as the most common getters and setters. There are two main types of dynamic insertion of getters and setters before. One is dynamic insertion at development time like Intellij and Eclipse. The disadvantage is that although you don’t have to write it manually, it still makes your code verbose. The other option is to add dynamically at run time with reflection through annotation-based services such as Spring, but this has the disadvantage of impacting performance and has some limitations.

The Github Repo portion of the article’s test code is referenced here

Quick Start

Installation

The development environment I am using is Intellij+Gradle. Here is only an introduction to this kind of construction method. The other ones based on Eclipse or Maven can be viewed on the official website homepage.

(1) Add Plugin in Intellij

  • Go to File > Settings > Plugins

  • Click on Browse repositories...

  • Search for Lombok Plugin

  • Click on Install plugin

  • Restart Android Studio

(2) Allow annotation processing

  • Settings -> Compiler -> Annotation Processors

Add dependencies to Gradle

The compile "org. Projectlombok: lombok: 1.12.6."Copy the code

Dynamic type derivation

Data Model: Data Model

Getter&Setter

The source code:

import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; public class GetterSetterExample { /** * Age of the person. Water is wet. * * @param age New value for this person's age. Sky is blue. * @return The current value of this person's age. Circles are round. */ @Getter @Setter private int age = 10; /** * Name of the person. * -- SETTER -- * Changes the name of this person. * * @param name The new value. */ @Setter(AccessLevel.PROTECTED) private String name; @Override public String toString() { return String.format("%s (age: %d)", name, age); }}Copy the code

Compiled code:

public class GetterSetterExample { /** * Age of the person. Water is wet. */ private int age = 10; /** * Name of the person. */ private String name; @Override public String toString() { return String.format("%s (age: %d)", name, age); } /** * Age of the person. Water is wet. * * @return The current value of this person's age. Circles are round. */ public int getAge() { return age; } /** * Age of the person. Water is wet. * * @param age New value for this person's age. Sky is blue. */ public void setAge(int age) { this.age = age; } /** * Changes the name of this person. * * @param name The new value. */ protected void setName(String name) { this.name = name; }}Copy the code

Lazy Getter

The source code:

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

After compiling:

public class GetterSetterExample { /** * Age of the person. Water is wet. */ private int age = 10; /** * Name of the person. */ private String name; @Override public String toString() { return String.format("%s (age: %d)", name, age); } /** * Age of the person. Water is wet. * * @return The current value of this person's age. Circles are round. */ public int getAge() { return age; } /** * Age of the person. Water is wet. * * @param age New value for this person's age. Sky is blue. */ public void setAge(int age) { this.age = age; } /** * Changes the name of this person. * * @param name The new value. */ protected void setName(String name) { this.name = name; }}Copy the code

Data

The source code:

import lombok.AccessLevel; import lombok.Setter; import lombok.Data; import lombok.ToString; @Data public class DataExample { private final String name; @Setter(AccessLevel.PACKAGE) private int age; private double score; private String[] tags; @ToString(includeFieldNames=true) @Data(staticConstructor="of") public static class Exercise { private final String name; private final T value; }}Copy the code

The compiled:

import java.util.Arrays; public class DataExample { private final String name; private int age; private double score; private String[] tags; public DataExample(String name) { this.name = name; } public String getName() { return this.name; } void setAge(int age) { this.age = age; } public int getAge() { return this.age; } public void setScore(double score) { this.score = score; } public double getScore() { return this.score; } public String[] getTags() { return this.tags; } public void setTags(String[] tags) { this.tags = tags; } @Override public String toString() { return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + ")"; } protected boolean canEqual(Object other) { return other instanceof DataExample; } @Override public boolean equals(Object o) { if (o == this) return true; if (! (o instanceof DataExample)) return false; DataExample other = (DataExample) o; if (! other.canEqual((Object)this)) return false; if (this.getName() == null ? other.getName() ! = null : ! this.getName().equals(other.getName())) 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; } @Override public int hashCode() { final int PRIME = 59; int result = 1; final long temp1 = Double.doubleToLongBits(this.getScore()); result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode()); result = (result*PRIME) + this.getAge(); result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32)); result = (result*PRIME) + Arrays.deepHashCode(this.getTags()); return result; } public static class Exercise { private final String name; private final T value; private Exercise(String name, T value) { this.name = name; this.value = value; } public static Exercise of(String name, T value) { return new Exercise(name, value); } public String getName() { return this.name; } public T getValue() { return this.value; } @Override public String toString() { return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")"; } protected boolean canEqual(Object other) { return other instanceof Exercise; } @Override public boolean equals(Object o) { if (o == this) return true; if (! (o instanceof Exercise)) return false; Exercise other = (Exercise) o; if (! other.canEqual((Object)this)) return false; if (this.getName() == null ? other.getValue() ! = null : ! this.getName().equals(other.getName())) return false; if (this.getValue() == null ? other.getValue() ! = null : ! this.getValue().equals(other.getValue())) return false; return true; } @Override public int hashCode() { final int PRIME = 59; int result = 1; result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode()); result = (result*PRIME) + (this.getValue() == null ? 43 : this.getValue().hashCode()); return result; }}}Copy the code

Object

Constructor

The source code

import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.AllArgsConstructor; import lombok.NonNull; @RequiredArgsConstructor(staticName = "of") @AllArgsConstructor(access = AccessLevel.PROTECTED) public class ConstructorExample { private int x, y; @NonNull private T description; @NoArgsConstructor public static class NoArgsExample { @NonNull private String field; }}Copy the code

After compiling:


public class ConstructorExample {

    private int x, y;

    @NonNull private T description;

    

    private ConstructorExample(T description) {

        if (description == null) throw new NullPointerException("description");

        this.description = description;

    }

    

    public static  ConstructorExample of(T description) {

        return new ConstructorExample(description);

    }

    

    @java.beans.ConstructorProperties({"x", "y", "description"})

    protected ConstructorExample(int x, int y, T description) {

        if (description == null) throw new NullPointerException("description");

        this.x = x;

        this.y = y;

        this.description = description;

    }

    

    public static class NoArgsExample {

        @NonNull private String field;

        

        public NoArgsExample() {

        }

    }

}
Copy the code

Builder

The source code:

package wx.toolkits.basic.class_object.utils.lombok.object; import lombok.experimental.Builder; import java.util.Set; @Builder public class BuilderExample { private String name; private int age; private Set occupations; public static void main(String args[]) { BuilderExample builderExample = BuilderExample.builder().build(); }}Copy the code

Compiled source code:


import java.util.Set;



public class BuilderExample {

    private String name;

    private int age;

    private Set occupations;

    

    BuilderExample(String name, int age, Set occupations) {

        this.name = name;

        this.age = age;

        this.occupations = occupations;

}

    

    public static BuilderExampleBuilder builder() {

        return new BuilderExampleBuilder();

    }

    

    public static class BuilderExampleBuilder {

        private String name;

        private int age;

        private java.util.ArrayList occupations;

        

        BuilderExampleBuilder() {

        }

        

        public BuilderExampleBuilder name(String name) {

            this.name = name;

            return this;

        }

        

        public BuilderExampleBuilder age(int age) {

            this.age = age;

            return this;

        }

        

        public BuilderExampleBuilder occupation(String occupation) {

            if (this.occupations == null) {

                this.occupations = new java.util.ArrayList();

            }

            

            this.occupations.add(occupation);

            return this;

        }

        

        public BuilderExampleBuilder occupations(Collection occupations) {

            if (this.occupations == null) {

                this.occupations = new java.util.ArrayList();

            }



            this.occupations.addAll(occupations);

            return this;

        }

        

        public BuilderExampleBuilder clearOccupations() {

            if (this.occupations != null) {

                this.occupations.clear();

            }

            

            return this;

        }



        public BuilderExample build() {

            // complicated switch statement to produce a compact properly sized immutable set omitted.

            // go to https://projectlombok.org/features/Singular-snippet.html to see it.

            Set occupations = ...;

            return new BuilderExample(name, age, occupations);

        }

        

        @java.lang.Override

        public String toString() {

            return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";

        }

    }

}
Copy the code

Exception: Exception processing

NonNull

The source code:

import lombok.NonNull; public class NonNullExample extends Something { private String name; public NonNullExample(@NonNull Person person) { super("Hello"); this.name = person.getName(); }}Copy the code

After compiling:

import lombok.NonNull; public class NonNullExample extends Something { private String name; public NonNullExample(@NonNull Person person) { super("Hello"); if (person == null) { throw new NullPointerException("person"); } this.name = person.getName(); }}Copy the code

SneakyThrows

The source code:

import lombok.SneakyThrows; public class SneakyThrowsExample implements Runnable { @SneakyThrows(UnsupportedEncodingException.class) public String utf8ToString(byte[] bytes) { return new String(bytes, "UTF-8"); } @SneakyThrows public void run() { throw new Throwable(); }}Copy the code

After compiling:

import lombok.Lombok; public class SneakyThrowsExample implements Runnable { public String utf8ToString(byte[] bytes) { try { return new String(bytes, "UTF-8"); } catch (UnsupportedEncodingException e) { throw Lombok.sneakyThrow(e); } } public void run() { try { throw new Throwable(); } catch (Throwable t) { throw Lombok.sneakyThrow(t); }}}Copy the code

Thread the Thread:

Synchronized

The source code:

import lombok.Synchronized; public class SynchronizedExample { private final Object readLock = 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

After compiling:

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

Utils

Cleanup

The source code:

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

After compiling:

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

Log Log:

Using @log or a similar annotation, you can automatically create a Log object for your class, which looks like this:


@CommonsLog

Creates private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

@Log

Creates private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());

@Log4j

Creates private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);

@Log4j2

Creates private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);

@Slf4j

Creates private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

@XSlf4j

Creates private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
Copy the code

Using Lombok, the code looks like this:

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

The compiled code looks like this:

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.error("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

Other parameters are as follows:

  • lombok.log.fieldName = an identifier (default: log)

The generated logger fieldname is by default ‘log’, but you can change it to a different name with this setting.

  • lombok.log.fieldIsStatic = [true | false] (default: true)

Normally the generated logger is a static field. By setting this key to false, the generated field will be an instance field instead.

  • lombok.log.flagUsage = [warning | error] (default: not set)

Lombok will flag any usage of any of the various log annotations as a warning or error if configured.

  • lombok.log.apacheCommons.flagUsage = [warning | error] (default: not set)

Lombok will flag any usage of @lombok.extern.apachecommons.CommonsLog as a warning or error if configured.

  • lombok.log.javaUtilLogging.flagUsage = [warning | error] (default: not set)

Lombok will flag any usage of @lombok.extern.java.Log as a warning or error if configured.

  • lombok.log.log4j.flagUsage = [warning | error] (default: not set)

Lombok will flag any usage of @lombok.extern.log4j.Log4j as a warning or error if configured.

  • lombok.log.log4j2.flagUsage = [warning | error] (default: not set)

Lombok will flag any usage of @lombok.extern.log4j.Log4j2 as a warning or error if configured.

  • lombok.log.slf4j.flagUsage = [warning | error] (default: not set)

Lombok will flag any usage of @lombok.extern.slf4j.Slf4j as a warning or error if configured.

  • lombok.log.xslf4j.flagUsage = [warning | error] (default: not set)

Lombok will flag any usage of @lombok.extern.slf4j.XSlf4j as a warning or error if configured.