La postura correcta para usar Lombok

En el mundo del desarrollo de Java, el complemento Lombok se ha convertido en una biblioteca de código muy popular. El complemento hace que el desarrollo de Java sea más fácil y eficiente, lo que aumenta la productividad del desarrollador.

1. ¿Qué es Lombok?

Lombok es una herramienta de desarrollo de Java que puede ayudar a los programadores a generar automáticamente código Java en tiempo de compilación a través de anotaciones, lo que simplifica el proceso de desarrollo de Java. Específicamente, mejorará la funcionalidad del código Java analizando anotaciones y luego generando código en tiempo de compilación.

La razón principal del complemento de Lombok es la sintaxis inflada del lenguaje Java, que requiere una gran cantidad de código repetitivo, así como métodos de obtención y configuración detallados e inflados. Cuando las capas de su modelo son muy grandes, escribir todo este código manualmente puede volverse muy tedioso y aburrido. Por lo tanto, el complemento de Lombok genera automáticamente código Java para nosotros y ayuda a optimizar el proceso de desarrollo de Java y mejorar la eficiencia.

2. Instalar Lombok

Abra la página de configuración de IDEA:

Busque "Lombok" en la página del complemento para instalar:

Nota: Para usar Lombok, debe instalar el complemento de Lombok en el IDE, para que el IDE pueda reconocer y usar correctamente las anotaciones de Lombok.

3. Spring Boot integra Lombok

Para usar el complemento de Lombok, debemos establecer dependencias en el proyecto. Aquí hay un ejemplo de cómo agregar el archivo pom.xml de Lombok usando Maven:

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

Nota: después de SpringBoot 2.1.x, no es necesario especificar la versión de Lombok. SpringBoot spring-boot-dependenciesha incorporado esta dependencia para la administración.

4. Usa Lombok

4.1 Lista de anotaciones

Las siguientes son algunas de las principales anotaciones proporcionadas por Lombok y sus funciones:

anotación Función
@Adquiridor Generar métodos getter para campos
@Setter Generar métodos setter para campos
@Datos Genere métodos getter y setter para campos, también incluye métodos equals, hashCode, toString
@Encadenar Genere un método toString para la clase
@EqualsAndHashCode Generar métodos equals y hashCode para clases
@NoArgsConstructor Generar un constructor sin argumentos para una clase
@AllArgsConstructor Generar un constructor con todos los campos para una clase.
@RequiredArgsConstructor @NonNullGenere constructores para clases con campos obligatorios (campos finales y anotados )
@Valor Genere propiedades de solo lectura (finales) para las clases, incluidos los métodos getter, equals, hashCode, toString
@Constructor Implementar el patrón Builder para clases.
@SneakyThrows Usado en un método, puede dejar que el método arroje una excepción comprobada sin usar explícitamente la palabra clave throws en el método
@Slf4j Agregue un objeto registrador SLF4J llamado 'registro' a la clase
@Limpiar Administrar automáticamente los recursos, que se utiliza para llamar automáticamente al método de cierre para liberar recursos
@NonNull Se usa para verificar si el parámetro del método o constructor es nulo, y si es nulo, se lanzará NullPointerException
@Delegar Genere automáticamente un método de delegado para reenviar la llamada al campo o método especificado
@Con Genere un método para un campo que devuelva un nuevo objeto con un valor actualizado para un campo
@superconstructor Patrón constructor para casos de herencia más complejos
@Sincronizado El bloqueo de sincronización proporcionado por Lombok, utilizado para métodos, se sincronizará en un campo privado, si es un método estático, se sincronizará en un campo estático privado
valor Definir una variable local y asignarle un valor inmediatamente.Esta variable es de tipo final y no se puede modificar

4.2 Introducción de uso parcial

La mayoría de los comentarios anteriores se pueden entender básicamente mirando la descripción de la función, y algunas de las instrucciones menos fáciles de entender se seleccionan a continuación.

@Getter(perezoso=verdadero)

@Getter(lazy=true)Genere métodos getter con inicialización diferida para los campos. Este método getter inicializa el campo la primera vez que se llama y almacena en caché el resultado. Por lo general, cuando un determinado atributo que debe obtenerse consume más recursos, puede agregar lazy=trueatributos a través de esta anotación para implementar la carga diferida, lo que generará un código repetitivo de Double Check Lock para cargar el atributo de forma diferida.

En Java, el patrón de "bloqueo de verificación doble" es una técnica común de programación simultánea de subprocesos múltiples, que se utiliza principalmente para retrasar la inicialización y garantizar que solo un subproceso pueda inicializar recursos. Cuando usa anotaciones en Lombok @Getter(lazy=true), Lombok generará el código de bloqueo verificado correspondiente. Esto garantiza la inicialización diferida de los campos, la seguridad de subprocesos en un entorno de subprocesos múltiples y la inicialización solo una vez.

import lombok.Getter;

public class LazyGetterExample {
    
    

    // 使用双重检查锁对方法进行加锁,确保只有一个线程可以执行 expensive() 方法(懒加载)
    @Getter(lazy = true)
    private final Double cached = expensive();

    private Double expensive() {
    
    
        // 模拟一个耗时的操作
        Double result = null;
        for (int i = 0; i < 1000000; i++) {
    
    
            result = Math.atan(i) * Math.tan(i);
        }
        return result;
    }

    public static void main(String[] args) {
    
    
        LazyGetterExample example = new LazyGetterExample();
        System.out.println(example.getCached());
    }
}

El código compilado se verá así:

import java.util.concurrent.atomic.AtomicReference;

public class LazyGetterExample {
    
    
    private final AtomicReference<Object> cached = new AtomicReference();

    public LazyGetterExample() {
    
    
    }

    private Double expensive() {
    
    
        Double result = null;

        for(int i = 0; i < 1000000; ++i) {
    
    
            result = Math.atan((double)i) * Math.tan((double)i);
        }

        return result;
    }

    public static void main(String[] args) {
    
    
        LazyGetterExample example = new LazyGetterExample();
        System.out.println(example.getCached());
    }

    public Double getCached() {
    
    
        Object value = this.cached.get();
        if (value == null) {
    
    
            synchronized(this.cached) {
    
    
                value = this.cached.get();
                if (value == null) {
    
    
                    Double actualValue = this.expensive();
                    value = actualValue == null ? this.cached : actualValue;
                    this.cached.set(value);
                }
            }
        }

        return (Double)((Double)(value == this.cached ? null : value));
    }
}

@Valor

@ValueGenera propiedades de solo lectura para las clases, es decir, todos los campos son final, incluidos getterlos métodos, equals, hashCode, toStringmétodos. En este momento, esta clase es equivalente a finalla clase y no se puede heredar, y sus atributos también se convertirán en finalatributos.

@Value
public class ValueExample {
    
    
    private String name;
    private int age;

    public static void main(String[] args) {
    
    
        // 只能使用全参构造器
        ValueExample example = new ValueExample("张三", 18);
        // 可以直接获取属性值
        System.out.println(example.getName());
        System.out.println(example.getAge());

        // 不能修改属性值
        // example.setName("李四");
        // example.setAge(20);
    }
}

El código compilado se verá así:

public final class ValueExample {
    
    
    private final String name;
    private final int age;

    public static void main(String[] args) {
    
    
        ValueExample example = new ValueExample("张三", 18);
        System.out.println(example.getName());
        System.out.println(example.getAge());
    }

    public ValueExample(final String name, final int age) {
    
    
        this.name = name;
        this.age = age;
    }

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

    public int getAge() {
    
    
        return this.age;
    }

    public boolean equals(final Object o) {
    
    
        if (o == this) {
    
    
            return true;
        } else if (!(o instanceof ValueExample)) {
    
    
            return false;
        } else {
    
    
            ValueExample other = (ValueExample)o;
            if (this.getAge() != other.getAge()) {
    
    
                return false;
            } else {
    
    
                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;
        result = result * 59 + this.getAge();
        Object $name = this.getName();
        result = result * 59 + ($name == null ? 43 : $name.hashCode());
        return result;
    }

    public String toString() {
    
    
        return "ValueExample(name=" + this.getName() + ", age=" + this.getAge() + ")";
    }
}

@Constructor

@BuilderImplemente el patrón de diseño Builder (builder pattern) para clases, generalmente utilizado para la construcción encadenada de objetos complejos.

import lombok.Builder;
import lombok.ToString;

@ToString
@Builder
public class BuilderExample {
    
    
    private String name;
    private int age;

    public static void main(String[] args) {
    
    
        BuilderExample example = BuilderExample.builder().name("张三").age(18).build();
        System.out.println(example);
    }
}

El código compilado se verá así:

public class BuilderExample {
    
    
    private String name;
    private int age;

    public static void main(String[] args) {
    
    
        BuilderExample example = builder().name("张三").age(18).build();
        System.out.println(example);
    }

    BuilderExample(final String name, final int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public static BuilderExampleBuilder builder() {
    
    
        return new BuilderExampleBuilder();
    }

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

    public static class BuilderExampleBuilder {
    
    
        private String name;
        private int age;

        BuilderExampleBuilder() {
    
    
        }

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

        public BuilderExampleBuilder age(final int age) {
    
    
            this.age = age;
            return this;
        }

        public BuilderExample build() {
    
    
            return new BuilderExample(this.name, this.age);
        }

        public String toString() {
    
    
            return "BuilderExample.BuilderExampleBuilder(name=" + this.name + ", age=" + this.age + ")";
        }
    }
}

@superconstructor

@SneakyThrows

@SneakyThrowsUsado en un método, puede dejar que el método genere una excepción comprobada sin usar explícitamente throwsla palabra clave para generar una excepción en el método.

import lombok.SneakyThrows;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class SneakyThrowsExample {
    
    
    // 自动抛出异常,不需要手动 try catch
    @SneakyThrows(UnsupportedEncodingException.class)
    public String sneakyMethod(){
    
    
        return URLEncoder.encode("Example", "Unsupported Encoding");
    }
    
    public static void main(String[] args) {
    
    
        SneakyThrowsExample example = new SneakyThrowsExample();
        System.out.println(example.sneakyMethod());
    }
}

El código compilado se verá así:

public class SneakyThrowsExample {
    
    
    public SneakyThrowsExample() {
    
    
    }

    public String sneakyMethod() {
    
    
        try {
    
    
            return URLEncoder.encode("Example", "Unsupported Encoding");
        } catch (UnsupportedEncodingException var2) {
    
    
            throw var2;
        }
    }

    public static void main(String[] args) {
    
    
        SneakyThrowsExample example = new SneakyThrowsExample();
        System.out.println(example.sneakyMethod());
    }
}

@Slf4j

Al usar Lombok para generar objetos de registro, hay varias anotaciones que se pueden usar según la implementación del registro. Por ejemplo @Log, @Log4j, @Log4j2, @Slf4jy así sucesivamente. Por @Slf4jejemplo , agrega un objeto registrador SLF4J llamado 'registro' a la clase.

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Slf4jExample {
    
    
    public static void main(String[] args) {
    
    
        log.info("Hello World");
        log.error("Hello World");
        log.debug("Hello World");
        log.warn("Hello World");
    }
}

El código compilado se verá así:

public class Slf4jExample {
    
    
    private static final Logger log = LoggerFactory.getLogger(Slf4jExample.class);

    public Slf4jExample() {
    
    
    }

    public static void main(String[] args) {
    
    
        log.info("Hello World");
        log.error("Hello World");
        log.debug("Hello World");
        log.warn("Hello World");
    }
}

@Limpiar

@CleanupSe usa para administrar recursos automáticamente y se usa para llamar automáticamente close()a métodos para liberar recursos, evitando la liberación manual.

public class CleanupExample {
    
    
    public static void main(String[] args) throws IOException {
    
    
        @Cleanup InputStream in = Files.newInputStream(Paths.get("file.txt"));
    }
}

El código compilado se verá así:

public class CleanupExample {
    
    
    public CleanupExample() {
    
    
    }

    public static void main(String[] args) throws IOException {
    
    
        InputStream in = new FileInputStream("/file.txt");
        if (Collections.singletonList(in).get(0) != null) {
    
    
            in.close();
        }
    }
}

@NonNull

@NonNullSe utiliza para comprobar si el parámetro del método o constructor es nulo. Si es nulo, se lanzará NullPointerException. Generalmente se utiliza para el juicio no nulo.

public class NonNullExample {
    
    
    public String nonNullMethod(@NonNull String string){
    
    
        return string;
    }
    
    public static void main(String[] args) {
    
    
        NonNullExample example = new NonNullExample();
        example.nonNullMethod(null);
    }
}

El código compilado se verá así:

public class NonNullExample {
    
    
    public NonNullExample() {
    
    
    }

    public String nonNullMethod(@NonNull String string) {
    
    
        if (string == null) {
    
    
            throw new NullPointerException("string is marked non-null but is null");
        } else {
    
    
            return string;
        }
    }

    public static void main(String[] args) {
    
    
        NonNullExample example = new NonNullExample();
        example.nonNullMethod((String)null);
    }
}

@Con

@WithUn método para la generación de campos que devuelve un nuevo objeto con un valor actualizado para un campo. En términos simples, puede clonar el objeto original y cambiar una de sus propiedades, y necesita especificar el método completo de construcción de parámetros al usarlo.

import lombok.AllArgsConstructor;
import lombok.With;

@With
@AllArgsConstructor
public class WithExample {
    
    
    private String name;
    private int age;

    public static void main(String[] args) {
    
    
        // 实例化一个对象
        WithExample example = new WithExample("javgo", 18);
        System.out.println(example);

        // 使用 withName 方法修改 name 属性
        WithExample withExample = example.withName("javgo2");
        System.out.println(withExample);
    }
}

El código compilado se verá así:

public class WithExample {
    
    
    private String name;
    private int age;

    public static void main(String[] args) {
    
    
        WithExample example = new WithExample("javgo", 18);
        System.out.println(example);
        WithExample withExample = example.withName("javgo2");
        System.out.println(withExample);
    }

    public WithExample withName(final String name) {
    
    
        return this.name == name ? this : new WithExample(name, this.age);
    }

    public WithExample withAge(final int age) {
    
    
        return this.age == age ? this : new WithExample(this.name, age);
    }

    public WithExample(final String name, final int age) {
    
    
        this.name = name;
        this.age = age;
    }
}

@Sincronizado

Cuando accedemos al mismo recurso en varios subprocesos, a menudo surgen problemas de seguridad de subprocesos y, a menudo, utilizamos synchronizedmétodos de modificación de palabras clave para lograr un acceso sincronizado. En cambio , el bloqueo de sincronización@Synchronized proporcionado por Lombok se usa para los métodos y se sincronizará en un campo privado.Si es un método estático, se sincronizará en un campo estático privado.

import lombok.Synchronized;

public class SynchronizedExample {
    
    
    private final Object readLock = new Object();

    @Synchronized
    public void syncMethod(){
    
    
        // do something
    }

    @Synchronized("readLock")
    public void customLockMethod() {
    
    
        // do something
    }

    public static void main(String[] args) {
    
    
        SynchronizedExample example = new SynchronizedExample();

        // 两个方法都会被锁定
        example.syncMethod(); // 锁定的是 this, 即 SynchronizedExample 对象
        example.customLockMethod(); // 锁定的是 readLock,即 SynchronizedExample.readLock 对象
    }
}

El código compilado se verá así:

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

    public SynchronizedExample() {
    
    
    }

    public void syncMethod() {
    
    
        synchronized(this.$lock) {
    
    
            ;
        }
    }

    public void customLockMethod() {
    
    
        synchronized(this.readLock) {
    
    
            ;
        }
    }

    public static void main(String[] args) {
    
    
        SynchronizedExample example = new SynchronizedExample();
        example.syncMethod();
        example.customLockMethod();
    }
}

valor

valSirve para definir una variable local de cualquier tipo y asignarle un valor inmediatamente.Esta variable es de finaltipo y no se puede modificar.

import lombok.val;
import java.util.ArrayList;

public class ValExample {
    
    
    public static void main(String[] args) {
    
    
        val example = new ArrayList<String>();
        example.add("Hello, World!");
    }
}

El código compilado se verá así:

public class ValExample {
    
    
    public ValExample() {
    
    
    }

    public static void main(String[] args) {
    
    
        ArrayList<String> example = new ArrayList();
        example.add("Hello, World!");
    }
}

Supongo que te gusta

Origin blog.csdn.net/ly1347889755/article/details/130996976
Recomendado
Clasificación