Introducción a los métodos y principios comunes de Lombok

Una herramienta que simplifica el código fuente y mejora la eficiencia de la programación, y se utiliza para generar código de uso común.

Dos paquetes:

  • lombok

  • lombok.experimental (propiedades experimentales)

como usar lombok

Introducir dependencias 

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>

instalar complemento 

código utilizado en

@Data
public class People {
    private String name;
}

Resumen de anotaciones comunes

@val

Al declarar una variable, el tipo de variable se puede inferir por sí mismo y viene con un atributo final,

@Datos

@ToString,@EqualsAndHashCode,@Getter,@Setter和@RequiredArgsConstrutor

@Slf4j

generar objeto de registro

@Valor

Similar a @Data, con las siguientes dos diferencias:

  • Se genera un constructor con parámetros completos;

  • Solo métodos getter, no métodos setter;

@Adquiridor

Métodos getter para todas las propiedades

@Setter

Setter métodos para todas las propiedades

@Constructor

Generar código para constructores encadenados

@Limpiar

Liberar o cerrar recursos de forma segura, el escenario más común es la operación de cerrar flujos en IO

@NonNull

getter: si la propiedad obtenida es nula, lanza NPE

setter: si el valor pasado es nulo al establecer la propiedad, lanzar NPE

@Encadenar

Generar método toString()

@SneakyThrows

Coma la excepción lanzada y reduzca algunos códigos de captura de prueba innecesarios

@NoArgsConstructor

Generar un constructor sin argumentos

@AllArgsConstructor

Agregar un constructor con todas las propiedades

@EqualsAndHashCode

Generar métodos equals() y hashcode()

@RequiredArgsConstructor

Se generará un constructor que contiene constantes y variables marcadas como NotNull

el caso

La parte comentada es el código que lombok nos ayudará a generar automáticamente.

@Slf4j

@Slf4j
public class Test {
    // private static final Logger log=LoggerFactory.getLogger(Test.class);
    public static void main(String[] args) {
        log.info("Hello world");
    }
}

@Constructor

        Test test = Test.builder()
                .id(id)
                .page(page)
                .build();

@Data
@Builder
public class Test {

    private String id;

    private String page;
    
    /**
     @java.beans.ConstructorProperties({"id", "page"})
    Test(Long id, int page) {
        this.id = id;
        this.page = page;
    }

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

    public TestBuilder toBuilder() {
        return new TestBuilder().id(this.id).page(this.page);
    }

    public static class TestBuilder {
        private Long id;
        private int page;

        TestBuilder() {}

        public TestBuilder id(Long id) {
            this.id = id;
            return this;
        }

        public TestBuilder page(int page) {
            this.page = page;
            return this;
        }

        public Test build() {
            return new Test(id, page);
        }

        public String toString() {
            return "Test.TestBuilder(id=" + this.id + ", page="
                + this.page")";
        }
    */
}

@SneakyThrows

    @Test(expected = RuntimeException.class)
    @SneakyThrows
    public void test_throw_exception() {
        when(HttpClientUtil.get(anyString()).thenThrow(new RuntimeException());
        api.test("nice");
    }

@Datos

@Data
public class User {

    private Long id;

    private String username;

    private String password;
    
    
    /**
    public User() {}

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

    public String getUsername() {return this.username;}

    public String getPassword() {return this.password;}

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

    public void setUsername(String username) {this.username = username; }

    public void setPassword(String password) {this.password = password; }

    public boolean equals(Object o) {
        if (o == this) { return true; }
        ...
        return true;
    }

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

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

    public String toString() {
        return "User(id=" + this.getId() + ...+ ")";
    }
    */
	}
}

@Valor

@Value
public class Test {

    (private final) Long id;

    (private final) String page;
    
    /**
    @java.beans.ConstructorProperties({"id", "page"})
    public Test(Long id, String page) {
        this.id = id;
        this.page = page;
    }

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

    public String getPage() {return this.page;}

    public boolean equals(Object o) {
        if (o == this) { return true; }
          ...
        return true;
    }

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

    public String toString() {
            return "Test.TestBuilder(id=" + this.id + ", page="
                + this.page")";
        }
    */
}

Convención de código Java

  • [Recomendación] Para clases de entidades inmutables con demasiados campos o demasiados parámetros de constructor, se recomienda usar lombok para generar el constructor.

  • [Recomendación] Antes de que se admitan datos de tipo Record, se recomienda que los campos de clase de entidad usen anotaciones lombok para generar setters y getters, y decidir si usar solo @Getter, @Setter o @Data de acuerdo con el principio de minimización

  • [Recomendación] En la programación de contratos, se recomienda utilizar la anotación no vacía de IDEA IntelliJ > Spring > anotación de Lombok para indicar que el parámetro no está vacío

pros y contras

ventaja

  • Reducir efectivamente la cantidad de código

  • dinámica. Por ejemplo, al agregar o restar campos, no hay necesidad de preocuparse por la modificación de métodos como Getter/Setter. 

  • Mejora la legibilidad del código hasta cierto punto.

defecto

  • Introduzca dependencias externas. Una vez que se use lombok en el paquete de recursos, otros tendrán que instalar complementos si quieren ver su código fuente.

  • El código generado no es intuitivo y es posible que no genere código como se esperaba

  • Integridad del código fuente reducida

problema comun

@Constructor

Problema del valor predeterminado de la propiedad. Si usa @Builder para generar código, el valor predeterminado del atributo no será válido. Debe usar @Builder.Default para marcar el atributo con el valor predeterminado, como:

    @Builder
    public class UserQueryParam {
        private Long id;
        private String username;
        @Builder.Default
        private int page = 1;
        @Builder.Default
        private int size = 15;
    }

@Adquiridor

Manejo especial de valores booleanos

private boolean test;

1. La regla de generación predeterminada para el método de lectura de atributos es es+nombre de atributo en lugar de obtener+nombre de atributo, es decir, esPrueba en lugar de obtenerPrueba

2. Si el nombre del atributo en sí comienza con is, como isTest, el método para obtener el atributo sigue siendo isTest, no el incómodo isIsTest

3. En las dos reglas anteriores, habrá una situación extrema causada por la irracionalidad, es decir, hay dos atributos, uno se llama isTest y el otro es test. Esto es esencialmente un problema de diseño. Para esta situación, el complemento -in El método de procesamiento es generar solo un isTest, en cuanto a qué atributo se lee, depende del orden de los atributos, prevaleciendo el primero.

@Valor y @Datos

@Value se usa a menudo para clases inmutables. Una clase inmutable significa que después de crear una instancia de la clase, las variables de instancia de la instancia no se pueden cambiar.

Similar a @Data, hay dos diferencias principales:

  • Se genera un constructor con parámetros completos;

  • Solo métodos getter, no métodos setter;

@Valor

@Datos

@Adquiridor

@Setter

@Encadenar

@EqualsAndHashCode

@RequiredArgsConstructor

@AllArgsConstructor 

@FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE)

Las anotaciones identificadas por @Value no se pueden usar junto con @RequestBody y jackson.

La razón por la que falla la deserialización de jackson después de usar @Value y fastjson puede tener éxito:

 1. Jackson lee el método set y @Value no genera el método set, por lo que falla; 

2. Fastjson lee el constructor y @Value genera el constructor, por lo que tiene éxito; 

Extensión: cuando use fastjson, use @Builder para verificar si se agrega @NoArgsConstructor o @AllArgsConstructor

Principio de Lombok

Modificar el árbol de sintaxis abstracta (AST) en tiempo de compilación

@Getter(AccessLevel.PUBLIC)
public class User {

    private Long id;

    private String username;

    @Getter(AccessLevel.PRIVATE)
    private String password;
}
public class User {

    private Long id;

    private String username;

    private String password;

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

    public String getUsername() {return this.username;

    // Field 优先级更高
    private String getPassword() {return this.password;}
}

árbol de sintaxis AST

introducir

Lombok se procesa en el enlace del árbol de sintaxis AST. AST es una representación de árbol utilizada para describir la estructura gramatical del código del programa. Cada nodo del árbol gramatical representa una estructura gramatical en el código del programa, como paquete, tipo, modificador, operadores , las interfaces, los valores devueltos e incluso los comentarios de código pueden ser una estructura gramatical.

muestra

En Idea, también puede ver el árbol de sintaxis AST del código instalando el complemento, como se muestra en la figura a continuación.

Cada atributo y cada método a la izquierda puede encontrar el nodo correspondiente a la derecha, por lo que al manipular los nodos del árbol AST, el código se puede agregar dinámicamente durante la compilación.

JSR 269 

Desde Java 6, javac ha comenzado a admitir la especificación API de procesamiento de anotaciones conectables JSR 269. Siempre que el programa implemente la API, las anotaciones definidas se pueden llamar cuando se compila el código fuente de Java. La esencia de Lombok es confiar en JSR 269 para realizar el uso del "Procesador de anotaciones" (herramienta de procesamiento de anotaciones) en la etapa de compilación de Javac para preprocesar las anotaciones personalizadas y generar un "Archivo de clase" que en realidad se ejecuta en la JVM.

En el diagrama esquemático anterior, se puede ver que el procesamiento de anotaciones es un paso entre el compilador que analiza el código fuente de Java y genera el archivo de clase.

lombok

Lombok es esencialmente un programa que implementa la " API JSR 269 ". En el proceso de uso de javac, el proceso específico de su función es el siguiente:

  1. javac analiza el código fuente y genera un árbol de sintaxis abstracta (AST)

  2. Llame al programa Lombok que implementa "JSR 269 API" durante la operación

  3. En este momento, Lombok procesa el AST obtenido en el primer paso, encuentra el árbol de sintaxis (AST) correspondiente a la clase donde se encuentra la anotación @Data y luego modifica el árbol de sintaxis (AST) para agregar los nodos de árbol correspondientes definidos por los métodos getter y setter

  4. javac usa el árbol de sintaxis abstracta modificado (AST) para generar archivos de código de bytes, es decir, agrega nuevos nodos (bloques de código) a la clase

Como se puede ver en el diagrama de flujo de la ejecución de Lombok anterior, después de analizar Javac en un árbol de sintaxis abstracta AST, Lombok modifica dinámicamente el AST de acuerdo con el procesador de anotaciones escrito por él mismo, agregando nuevos nodos (es decir, la anotación personalizada de Lombok necesita para generar código), y finalmente generar un archivo de clase de bytecode ejecutable JVM a través del análisis.

código central

Múltiples anotaciones personalizadas en Lombok tienen clases de procesamiento de controlador correspondientes. Son estas clases de controlador las que realmente reemplazan, modifican y procesan sus anotaciones personalizadas en Lombok. Para obtener detalles de su implementación, consulte el código.

complemento lombok

Cuando se llama al método omitido usando la anotación Lombok, se informará un error de que no se puede encontrar la definición. En este caso, se requiere un procesamiento especial. Por ejemplo, en Intellij Idea, se debe descargar e instalar el complemento Lombok.

Supongo que te gusta

Origin blog.csdn.net/xue_xiaofei/article/details/126145975
Recomendado
Clasificación