阿昌教你使用常用Lombok@注解

阿昌教你使用常用Lombok@注解,第1张

阿昌教你使用常用Lombok@注解 前言

老铁/老妹们好 (。・∀・)ノ゙!

今天阿昌分享的是常用的Lombok注解,官方地址,github地址

做Java开发的,哪个不知道这小辣椒呢。Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,提高开发人员的开发效率,通过使用对应的注解,可以在编译源码的时候生成对应的方法


IDEA安装
  • 安装插件

  • 引入依赖

    org.projectlombok
    lombok


常用注解

官方注解的介绍

1、@Data

@Data is a convenient shortcut annotation that bundles the features of @ToString, @EqualsAndHashCode, @Getter / @Setter and @RequiredArgsConstructor is a convenient shortcut annotation that bundles the features of @ToString, @EqualsAndHashCode, @Getter / @Setter and @RequiredArgsConstructor together

@Data注解在类上,会为类的所有属性自动生成setter/getter、equals、canEqual、hashCode、toString方法。

  • 注意点

    • 带有注解的参数(如callSuper、includeFieldNames和exclude)不能用 设置@Data
    • 所有生成的 getter 和 setter 都是public. 要覆盖访问级别,请使用显式@Setter和/或@Getter注释对字段或类进行注释
    • 所有标记为的字段transient都不会被考虑用于hashCode和equals。
    • 所有静态字段都将被完全跳过(不考虑任何生成的方法,并且不会为它们制作 setter/getter)。
    • @Data(staticConstructor="of") class Foo { private T x;}您可以Foo通过编写:Foo.of(5);而不是必须编写:来创建新实例new Foo(5);。
  • 使用Lombok

    @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;
        }
    }
    
  • 不使用Lombok

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;
        }
    }
    
}

2、@Getter/@Setter

You can annotate any field with @Getter and/or @Setter, to let lombok generate the default getter/setter automatically.

使用@Getter和/或注释任何字段@Setter,让 lombok 自动生成默认的 getter/setter。

  • 注意点
    • 默认 getter 仅返回该字段,并getFoo()在该字段被调用foo(或isFoo该字段的类型为boolean)时命名。
    • setFoo()如果该字段被调用foo、返回void并采用与该字段相同类型的 1 个参数,则会命名默认设置器。它只是将字段设置为此值。
    • 可以使用注解属性中AccessLevel.NONE来设置访问级别,为任何字段手动禁用 getter/setter 生成。
  • 使用Lombok
public class GetterSetterExample {
    @Getter @Setter 
    private int age = 10;

    @Setter(AccessLevel.PROTECTED) //生成set方法,并指定范围为protected
    private String name;

    @Override 
    public String toString() {
        return String.format("%s (age: %d)", name, age);
    }
}
  • 不使用Lombok
public class GetterSetterExample {
    private int age = 10;
    private String name;
    @Override public String toString() {
        return String.format("%s (age: %d)", name, age);
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    protected void setName(String name) {
        this.name = name;
    }
}

3、@NonNull

You can use @NonNull on a record component, or a parameter of a method or constructor. This will cause to lombok generate a null-check statement for you.

@NonNull在记录组件、方法或构造函数的参数上使用。lombok 会为此生成一个空检查语句。

  • 配置项

可选择指定,如果出错后抛出的异常是什么

lombok.nonNull.exceptionType= [ NullPointerException| IllegalArgumentException| JDK| Guava| Assertion]
#(默认值:)NullPointerException。
  • 使用Lombok
public class NonNullExample extends Something {
    private String name;

    public NonNullExample(@NonNull Person person) {
        super("Hello");
        this.name = person.getName();
    }
}
  • 不使用Lombok
public class NonNullExample extends Something {
    private String name;
    public NonNullExample(@NonNull Person person) {
        super("Hello");
        if (person == null) {
            throw new NullPointerException("person is marked @NonNull but is null");
        }
        this.name = person.getName();
    }
}

4、@Cleanup

You can use @Cleanup to ensure a given resource is automatically cleaned up before the code execution path exits your current scope

@Cleanup可在代码执行路径退出当前范围之前自动清理给定资源

  • 注意点

    • @Cleanup InputStream in = new FileInputStream("some/file");
      //在所在范围的末尾,in.close()会被调用。
      
    • 如果您要清理的对象类型没有close()方法,但有其他一些无参数方法,则需要在注解属性中指定那个关闭方法,如:

      @Cleanup("dispose")
      
  • 使用Lombok

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);
        }
    }
}
  • 不使用Lombok
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();
            }
        }
    }
}

5、@EqualsAndHashCode

Any class definition may be annotated with @EqualsAndHashCode to let lombok generate implementations of the equals(Object other) and hashCode() methods

使用注释@EqualsAndHashCode来让 lombok 生成equals(Object other)和hashCode()方法的实现

  • 注意点

    • 为类自动生成equalsandhashCode方法是一个不好的想法,因为其父类也可能定义了字段,这些字段也需要 equals/hashCode 代码,所以该类就不会生成方法。
    • 通过设置callSuper到真正的,可以包括equals和hashCode你的父类中生成的方法的方法。
  • 使用Lombok

@EqualsAndHashCode
public class EqualsAndHashCodeExample {
    private transient int transientVar = 10;
    private String name;
    private double score;
    //指定不为该属性,生成对应的EqualsAndHashCode
    @EqualsAndHashCode.Exclude private Shape shape = new Square(5, 10);
    private String[] tags;
    //指定不为该属性,生成对应的EqualsAndHashCode
    @EqualsAndHashCode.Exclude private int id;
    public String getName() {
        return this.name;
    }
    
    //callSuper为父类也生成EqualsAndHashCode
    @EqualsAndHashCode(callSuper=true)
    public static class Square extends Shape {
        private final int width, height;

        public Square(int width, int height) {
            this.width = width;
            this.height = height;
        }
    }
}
  • 不使用Lombok
public class EqualsAndHashCodeExample {
    private transient int transientVar = 10;
    private String name;
    private double score;
    private Shape shape = new Square(5, 10);
    private String[] tags;
    private int id;

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

    @Override public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof EqualsAndHashCodeExample)) return false;
        EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
        if (!other.canEqual((Object)this)) return false;
        if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
        if (Double.compare(this.score, other.score) != 0) return false;
        if (!Arrays.deepEquals(this.tags, other.tags)) return false;
        return true;
    }

    @Override public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final long temp1 = Double.doubleToLongBits(this.score);
        result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode());
        result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
        result = (result*PRIME) + Arrays.deepHashCode(this.tags);
        return result;
    }

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

    public static class Square extends Shape {
        private final int width, height;

        public Square(int width, int height) {
            this.width = width;
            this.height = height;
        }

        @Override public boolean equals(Object o) {
            if (o == this) return true;
            if (!(o instanceof Square)) return false;
            Square other = (Square) o;
            if (!other.canEqual((Object)this)) return false;
            if (!super.equals(o)) return false;
            if (this.width != other.width) return false;
            if (this.height != other.height) return false;
            return true;
        }

        @Override public int hashCode() {
            final int PRIME = 59;
            int result = 1;
            result = (result*PRIME) + super.hashCode();
            result = (result*PRIME) + this.width;
            result = (result*PRIME) + this.height;
            return result;
        }

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

6、@ToString

Any class definition may be annotated with @ToString to let lombok generate an implementation of the toString() method.

任何类定义都可以使用注释@ToString来让 lombok 生成toString()方法的实现。

  • 注意点
    • 默认情况下,将打印所有非静态字段,并会按顺序打印您的类名以及每个字段,并以逗号分隔。
    • 通过将includeFieldNames参数设置为*true,*您可以为toString()方法的输出增加一些清晰度(但也有一定的长度)。
    • 可使用@ToString.Exclude,来跳过你想跳过的某些字段。
    • 设置callSuper为true,可以将父类的toString的输出包含到输出中。
    • 可以通过@ToString.Include(rank = -1),来更改成员的打印顺序。
      • rank的默认值为0
      • 更高等级的成员首先打印
      • 相同等级的成员按照它们在源文件中出现的相同顺序打印。
  • 使用Lombok
@ToString
public class ToStringExample {
    private static final int STATIC_VAR = 10;
    private String name;
    private Shape shape = new Square(5, 10);
    private String[] tags;
    @ToString.Exclude private int id;

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

    @ToString(callSuper=true, includeFieldNames=true)
    public static class Square extends Shape {
        private final int width, height;

        public Square(int width, int height) {
            this.width = width;
            this.height = height;
        }
    }
}
  • 不使用Lombok
public class ToStringExample {
    private static final int STATIC_VAR = 10;
    private String name;
    private Shape shape = new Square(5, 10);
    private String[] tags;
    private int id;

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

    public static class Square extends Shape {
        private final int width, height;

        public Square(int width, int height) {
            this.width = width;
            this.height = height;
        }

        @Override 
        public String toString() {
            return "Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";
        }
    }

    @Override 
    public String toString() {
        return "ToStringExample(" + this.getName() + ", " + this.shape + ", " + Arrays.deepToString(this.tags) + ")";
    }
}

7、@NoArgsConstructor/@RequiredArgsConstructor/@AllArgsConstructor

This set of 3 annotations generate a constructor that will accept 1 parameter for certain fields, and simply assigns this parameter to the field.

生成一个构造函数,该构造函数将接受某些字段的 1 个参数,并简单地将此参数分配给该字段。

  • 注意点
    • @NoArgsConstructor
      • 将生成一个无参构造器。
      • 如果该类,存在只有一个没有初始化的final属性,那就会编译出错,可通过@NoArgsConstructor(force = true),为final属性初始化0/ false/ null
    • @RequiredArgsConstructor
      • 生成一个带有 1 个参数的构造器。
      • 所有未初始化的final字段都会获得一个参数0/ false/ null
    • @AllArgsConstructor
      • 为类中的每个字段生成一个带有 1 个参数的构造器。
  • 使用Lombok
//指定一个静态构造方法,名为"of"
@RequiredArgsConstructor(staticName = "of")
//access指定构造器描述范围
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample {
    private int x, y;
    @NonNull 
    private T description;

    @NoArgsConstructor
    public static class NoArgsExample {
        @NonNull 
        private String field;
    }
}
  • 未使用Lombok
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() {
        }
    }
}

8、@Builder

The @Builder annotation produces complex builder APIs for your classes.

为类生成一个静态复杂的构建器 API

  • 注意点

    • 为目标类Foo,生成一个内部类FooBuilder,具有与静态方法(称为builder)相同的类型参数。

      • FooBuilder含
        • 有目标类非静态的每个属性,且私有的非静态非最终字段。
        • 一个包私有无参数空构造函数。
        • toString()实现
        • build()调用方法,传入每个字段的方法。它返回与目标返回的相同类型的类。
        • 目标的每个参数的类似“setter”的方法
    • @Builder.Default字段 上的初始化程序被删除并存储在静态方法中,以确保如果在构建中指定了值,则该初始化程序根本不会被执行。这确实意味着初始化程序不能引用this,super或任何非静态成员。如果 lombok 为你生成一个构造函数,它也会用初始化器初始化这个字段。

    • @Singular只能用于的集合类型。

  • 使用Lombok

@Builder
public class BuilderExample {
    @Builder.Default 
    private long created = System.currentTimeMillis();
    private String name;
    private int age;
    @Singular 
    private Set occupations;
}
  • 不使用Lombok
public class BuilderExample {
    private long created;
    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;
    }

    private static long $default$created() {
        return System.currentTimeMillis();
    }

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

    public static class BuilderExampleBuilder {
        private long created;
        private boolean created$set;
        private String name;
        private int age;
        private java.util.ArrayList occupations;

        BuilderExampleBuilder() {
        }

        public BuilderExampleBuilder created(long created) {
            this.created = created;
            this.created$set = true;
            return this;
        }

        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.
            Set occupations = ...;
            return new BuilderExample(created$set ? created : BuilderExample.$default$created(), name, age, occupations);
        }

        @java.lang.Override
            public String toString() {
            return "BuilderExample.BuilderExampleBuilder(created = " + this.created + ", name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
        }
    }
}
  • 使用案例
Person.builder().age(1).name("achang").build();

9、@Log

You put the variant of @Log on your class (whichever one applies to the logging system you use); you then have a static final log field, initialized as is the commonly prescribed way for the logging framework you use, which you can then use to write log statements.

从静态工厂中获取一个打印日志的对象

  • 注意点

    • 有多种日志种类可供选择:

      • @CommonsLog

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

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

        private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
        
      • @Log

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

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

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

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

        private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
        
      • @CustomLog

        private static final com.foo.your.Logger log = com.foo.your.LoggerFactory.createYourLogger(LogExample.class);
        
  • 使用Lombok

@Log
public class LogExample {
    public static void main(String... args) {
        log.severe("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");
    }
}
  • 不使用lombok
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.severe("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");
    }
}

10、@SneakyThrows

@SneakyThrows can be used to sneakily throw checked exceptions without actually declaring this in your method’s throws clause. This somewhat contentious ability should be used carefully

@SneakyThrows可用于自动的抛出已检查的异常,而无需在方法的throws子句中实际声明。

  • 使用Lombok
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();
    }
}
  • 不使用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);
        }
    }
}

11、@Accessors

The @Accessors annotation is used to configure how lombok generates and looks for getters and setters.

链式调用,在@Accessors龙目岛是如何产生并寻找getter和setter方法的注释用于配置。

  • 注意点

    • chain– 一个布尔值。如果为true,则生成的 setter 返回this而不是void。
      默认值:false,除非fluent=true,然后默认值:true
  • 使用案例

public class TestLombok {
    public static void main(String[] args) {
        Person achang = Person.builder().age(1).name("achang").build();
        achang.setAge(18).setName("阿昌");
    }

    @Data
    @Builder
    @Accessors(chain = true)
    public static class Person{
        private Integer age;
        private String name;
    }
}
Lombok的优缺点

又到了Lombok最具有争议性的话题了,他的优缺点。

  • 优点
    • 让代码更加的简洁干净
    • 开发时,只需要在实体类上标记注解即可,提升了开发的效率
  • 缺点
    • 不支持多种参数构造器的重载
    • 大大降低了源代码的可读性和完整性,降低了阅读源代码的舒适度(因为会省略很多东西)
    • 它会十分严重影响打包的效率

结尾

Lombok最大的优点就是让代码更加的简洁干净,但是我们从上面的各个注解看过来,有一些的注解会改变我们的编码习惯,让我们后期去查看源码的时候,就不能按照Java官方的语法的查看,而是Lombok的编码。

但要记住,它只是一个工具,这个工具再怎么强大,也是要被使用者使用。Lombok有它的许许多多的优点,也有它逃避不了的缺点,我们需要做的是熟练的知道其优缺点,在我们实战中灵活运用才是王道。

以上就是这次分享的所有内容,感谢你能看到这里 (๑′ㅂ`๑)

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5685950.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存