zoukankan      html  css  js  c++  java
  • lombok使用总结

    前提

    这篇文章主要介绍lombok的使用,至于lombok的源码和原理暂不探究,可以看上一篇文章插件化注解处理API去了解lombok的基本原理。参考资料:

    简介

    Project Lombok是一个java库,它可以自动插入到编辑器中,并构建工具,使java更加丰富。再也不用getter或equals方法了。尽早访问未来的java特性,比如val等等。这个就是lombok的官方简介(例如Jdk9中新增的val关键字在lombok中很早就出现了)。lombok实际上是基于JSR-269的插件化注解处理API,在编译期间对使用了特定注解的类、方法、属性或者代码片段进行动态修改,添加或者实现其自定义功能的类库。

    安装

    maven依赖

    在项目中使用到lombok的注解必须引入其依赖:

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

    当前的最新版本为:1.16.20。

    插件

    如果不为IDE安装lombok的插件,IDE无法识别lombok编译期动态生成的代码,表现为代码块标红,因此需要安装其插件,插件地址:https://projectlombok.org/download。

    下载完成后,将会得到一个jar包lombok-xx.xx.xx.jar,直接使用命令java -jar lombok-xx.xx.xx.jar运行即可,然后按照指引安装到IDEA、eclipse或者myeclipse。

    lombok注解

    @val

    @val用于声明修饰符为final的局部变量类型,使用的时候不需要编写实际的类型,这一点依赖于编译器的类型推导。@val的作用域是局部变量。举例如下:

    使用lombok:

    
     import java.util.ArrayList;
    import java.util.HashMap;
    import lombok.val;
    
    public class ValExample {
      public String example() {
        val example = new ArrayList<String>();
        example.add("Hello, World!");
        val foo = example.get(0);
        return foo.toLowerCase();
      }
    }  
    

    相当于原生Java:

    
     import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Map;
    
    public class ValExample {
      public String example() {
        final ArrayList<String> example = new ArrayList<String>();
        example.add("Hello, World!");
        final String foo = example.get(0);
        return foo.toLowerCase();
      }
    }
    

    @var

    @var的功能类似于@val,不过@var修饰的是非final修饰的局部变量。

    @NonNull

    @NonNull的作用域是属性(field)、方法参数或、构造函数参数以及局部变量(LOCAL_VARIABLE),为这些参数添加一个空检查语句,基本格式是:if(param == null) {throw new NullPointerException("param ");}

    使用lombok:

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

    相当于原生Java:

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

    @Cleanup

    你可以使用@Cleanup来确保在代码执行路径退出当前范围之前自动清理给定的资源,一般使用在流的局部变量的关闭。可以通过value()指定关闭资源的方法名,注意,关闭资源的方法必须是无参void方法,默认的关闭资源方法名称是"close"。

    使用lombok:

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

    相当于原生Java:

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

    @Getter/@Setter

    @Getter/@Setter作用域是属性或者类。@Getter为指定属性或者类中的所有属性生成Getter方法,@Setter指定非final属性或者类中的所有非final属性生成Setter方法。可以通过@Getter/@Setter的value()中的AccessLevel属性来指定生成的方法的修饰符,可以通过@Getter的布尔值属性lazy来指定是否延迟加载。

    使用lombok:

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

    相当于原生Java:

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

    @ToString

    @ToString的作用域是类,主要作用是覆盖类中的toString方法。@ToString的属性比较多,简介如下:

    • includeFieldNames():布尔值,默认为true,true表示拼接toString的时候使用属性名。
    • exclude():字符串数组,默认为空,用于通过属性名排除拼接toString时使用的属性。
    • of():exclude()属性的对立属性,意思就是include。
    • callSuper():布尔值,默认为false,是否调用父类的属性。
    • doNotUseGetters():布尔值,默认为false,true表示拼接toString的时候使用属性值而不是其Getter方法。

    下面是官方例子:

    使用lombok:

    import lombok.ToString;
    
    @ToString(exclude="id")
    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.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;
        }
      }
    }
    

    相当于原生Java:

    import java.util.Arrays;
    
    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) + ")";
      }
    }
    

    @EqualsAndHashCode

    @EqualsAndHashCode的作用域是类,用于生成equals()和hashCode()方法。此注解的属性比较多,不过和@ToString类似。举例如下:

    使用lombok:

    import lombok.EqualsAndHashCode;
    
    @EqualsAndHashCode(exclude={"id", "shape"})
    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;
      }
      
      @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;
        }
      }
    }
    

    相当于原生Java:

    import java.util.Arrays;
    
    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;
        }
      }
    }
    

    @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor

    这三个注解的作用域都是类。@NoArgsConstructor作用是生成一个无参数的构造函数。@AllArgsConstructor作用是生成一个具有所有字段的构造函数。@RequiredArgsConstructor的作用是为每一个使用了final或者@NonNull修饰的属性都生成一个只有一个参数的构造函数。这三个注解都可以通过staticName()指定构造的命名,通过access()指定构造的修饰符。@NoArgsConstructor的属性force()默认值为false,当类中存在final属性的时候使用了@NoArgsConstructor会编译错误,如果force()值为true,那么会把final修饰的属性作为"无参数构造"的参数,并且把属性赋值为0、null或者false。

    使用lombok:

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

    相当于原生Java:

    
     public class ConstructorExample<T> {
      private int x, y;
      @NonNull private T description;
      
      private ConstructorExample(T description) {
        if (description == null) throw new NullPointerException("description");
        this.description = description;
      }
      
      public static <T> ConstructorExample<T> of(T description) {
        return new ConstructorExample<T>(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() {
        }
      }
    }
    

    @Data

    @Data的作用域是类,相当于同时应用了@Getter、@Setter、@ToString、@EqualsAndHashCode、@RequiredArgsConstructor。如果已经显示自定义过构造函数,就不会再自动生成构造函数了。举例如下:

    使用lombok:

    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<T> {
        private final String name;
        private final T value;
      }
    }
    

    相当于原生Java:

    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<T> {
        private final String name;
        private final T value;
        
        private Exercise(String name, T value) {
          this.name = name;
          this.value = value;
        }
        
        public static <T> Exercise<T> of(String name, T value) {
          return new Exercise<T>(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;
        }
      }
    }
    

    @Value

    @Value的作用域是类,和@Data类似,但是用于不可变类型。生成的类和所有字段都设置为final,所有字段都为private,自动生成Getter但是没有Setter,会生成初始化所有字段的构造函数。相当于同时应用了final、 @ToString、 @EqualsAndHashCode、 @AllArgsConstructor 、@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)和@Getter。

    使用lombok:

    import lombok.AccessLevel;
    import lombok.experimental.NonFinal;
    import lombok.experimental.Value;
    import lombok.experimental.Wither;
    import lombok.ToString;
    
    @Value public class ValueExample {
      String name;
      @Wither(AccessLevel.PACKAGE) @NonFinal int age;
      double score;
      protected String[] tags;
      
      @ToString(includeFieldNames=true)
      @Value(staticConstructor="of")
      public static class Exercise<T> {
        String name;
        T value;
      }
    }
    

    相当于原生Java:

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

    @Builder

    @Builder的作用域是类,使用此注解后类中新增一个成员类(Builder)将会使用构建者模式,编译时增加了一个Builder内部类和全字段的构造器。@Builder.Default用于指定Builder中的属性的默认值,@Singular用于告诉lombok当前属性类型是集合类型,lombok会为信任的集合类型添加"adder"方法而不是"setter"方法。

    使用lombok:

    import lombok.Builder;
    import lombok.Singular;
    import java.util.Set;
    
    @Builder
    public class BuilderExample {
      @Builder.Default private long created = System.currentTimeMillis();
      private String name;
      private int age;
      @Singular private Set<String> occupations;
    }
    

    相当于原生Java:

    
     import java.util.Set;
    
    public class BuilderExample {
      private long created;
      private String name;
      private int age;
      private Set<String> occupations;
      
      BuilderExample(String name, int age, Set<String> 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<String> 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<String>();
          }
          
          this.occupations.add(occupation);
          return this;
        }
        
        public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
          if (this.occupations == null) {
            this.occupations = new java.util.ArrayList<String>();
          }
    
          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<String> 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 + ")";
        }
      }
    }
    

    @Synchronized

    @Synchronized的作用域是方法,用于方法同步,使用此注解后,方法体中的代码块自动包含在一个synchronize块中。synchronize块加锁的对象一定是类中的一个成员属性,可以通过@Synchronized的value()指定,如果不存在则由lombok新建,一般是private final Object $lock = new Object[0];

    使用lombok:

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

    相当于原生Java:

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

    @SneakyThrows

    @SneakyThrows的作用域是构造或者方法,用于自动捕获(隐藏)检查异常。我们知道,java对于检查异常,需要在编码时进行捕获,或者抛出。该注解的作用是将检查异常包装为运行时异常,那么编码时就无需处理异常了。

    提示:不过这并不是友好的编码方式,因为你编写的api的使用者,不能显式的获知需要处理检查异常。

    使用lombok:

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

    相当于原生Java:

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

    @Log

    @Log的作用域是类,用于生成日志API句柄。目前支持的类型如下:

    @CommonsLog 
    相当于在类中定义了:private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
    @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);
    

    使用lombok:

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

    相当于原生Java:

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

    小结

    其实从实现的角度来看,lombok并不是一个十分奇特的框架,它用到的技术已经是"很老的"Jdk6的一个特性,但是它表现出来的特性确实令人感觉它就是奇技淫巧。毕竟是奇技淫巧,很多不了解的人就会望然生畏,觉得使用了它很可能会导致系统出现无法预知的BUG之类(这里吐槽一下,笔者所在的公司禁用lombok)。其实,基于插件化注解处理API生成代码是位于编译期间,如果出现任何问题,很明显编译是不可能通过的。如果觉得lombok有问题,大可以去翻看每一个编译后的文件,看它们有没有表现异常。lombok在日常编码中可以极大提高效率,因此它一定是百益而无一害的。

    (全文完)

    技术公众号(《Throwable文摘》),不定期推送笔者原创技术文章(绝不抄袭或者转载):

    娱乐公众号(《天天沙雕》),甄选奇趣沙雕图文和视频不定期推送,缓解生活工作压力:

  • 相关阅读:
    GetClassLoader和GetCallerClass的使用
    Maven的生命周期和插件
    对象池原理简要描述
    Git x SVN rebase事故
    Git 二进制文件冲突解决
    Git x SVN 当前工作流程
    Laya 项目解耦
    Laya 利用JS进行反射
    Laya Tween 和 遮罩
    Laya Tween循环
  • 原文地址:https://www.cnblogs.com/throwable/p/9139922.html
Copyright © 2011-2022 走看看