Android 常用插件之 LomBok

一 介绍

      lomBok 是通过使用对应的注解,可以在编译源码的时候生成对应的方法,减少模板代码的编写。

二 集成

     AS  在build.gradle  添加如下依赖

     compile 'javax.annotation:javax.annotation-api:1.2'

     compile 'org.projectlombok:lombok:1.16.18'

     然后安装lombok插件


三   使用常见注解  及 编译时生成对应的方法

官方注解:https://projectlombok.org/features/all

1   @Setter @Getter    可以修饰javaBean 的类 【编译时让该类生成所有参数的set get方法】  也可以 修饰制定字段上   编译生成对应的setget方法;可以使用可选参数来指定生成的方法的访问级别 如

    @Getter @Setter private boolean employed = true;
    @Setter(AccessLevel.PROTECTED) private String name;     // AccessLevel.PROTECTED  来指定 生成的set方法为

protected 

    相当于java源码为:

private boolean employed = true;
private String name;

public boolean isEmployed() {
    return employed;
}

public void setEmployed(final boolean employed) {
    this.employed = employed;
}

protected void setName(final String name) {
    this.name = name;
}

 2 @ToString : 生成对应的toString方法。按参数顺序 按照key=value形式依次打印,按照,号分割;

    @ToString(exclude = {"id","name"})   用exclude 决定排除哪些参数

     @ToString(callSuper = true)  决定调用父类同名方法

    例如:  生成toString   调用  父类同名方法 排除someExcludedField字段

@ToString(callSuper=true,exclude="someExcludedField")
public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
}

  相当于 java源码:

public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
    
    @java.lang.Override
    public java.lang.String toString() {
        return "Foo(super=" + super.toString() +
            ", someBoolean=" + someBoolean +
            ", someStringField=" + someStringField + ")";
    }
}

3 @EqualsAndHashCode   生成对应的equals() 和 hashCode()方法  ,默认情况下  非static 和非transient 都被使用。也可以用exclude排除字段,,callSuper = true调用父类方法等;当父类重写的@EqualsAndHashCode   子类要声明是否调用父类的同名 方法

   如父类

@EqualsAndHashCode
public class UBean {
    private String school;
}

  子类

@EqualsAndHashCode(callSuper = true, exclude = {"value"})
public class TestBean extends UBean {
    private transient int transientVar = 10;
    private static String active;
    private int value;
    private String name;
}

  相当于Java源码为:    如下结果  不包括 static 和 transient 和exclude = {"value"}声明的字段  并调用了父类同名方法

public class TestBean extends UBean {
    private transient int transientVar = 10;
    private static String active;
    private int value;
    private String name;

    public TestBean() {
    }

    public boolean equals(Object o) {
        if(o == this) {
            return true;
        } else if(!(o instanceof TestBean)) {
            return false;
        } else {
            TestBean other = (TestBean)o;
            if(!other.canEqual(this)) {
                return false;
            } else if(!super.equals(o)) {
                return false;
            } else {
                Object this$name = this.name;
                Object other$name = other.name;
                if(this$name == null) {
                    if(other$name != null) {
                        return false;
                    }
                } else if(!this$name.equals(other$name)) {
                    return false;
                }

                return true;
            }
        }
    }

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

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

4 @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor

   给类增加无参构造器        指定参数的构造器                     包含所有参数的构造器

 @NoArgsConstructor 生成一个无参构造方法。当类中有final字段没有被初始化时,编译器会报错,此时可用   @NoArgsConstructor(force = true),然后就会为没有初始化的final字段设置默认值 0 / false / null。对于具有约束的字段 (例如@NonNull字段),不会生成检查或分配,因此请注意,正确初始化这些字段之前,这些约束无效。

   @NoArgsConstructor :
@NoArgsConstructor(force = true)
public class TestBean extends UBean {
    private transient int transientVar = 10;
    private static String active;
    private final int value;
    private String name;
}

@RequiredArgsConstructor : (指定参数构造器)只能为 未初始化的 final 字段和使用 @NonNull 标注的字段生成构造函数

@RequiredArgsConstructor(staticName = "of")会生成一个of()的静态方法,并把构造方法设置为私有的

@RequiredArgsConstructor 

@RequiredArgsConstructor
public class TestBean {
    @NonNull private Integer id ;
    @NonNull private String name ;
    private int fa;
}

对应.class  文件为:

public class TestBean {
    @NonNull
    private Integer id;
    @NonNull
    private String name;
    private int fa;

    public TestBean(@NonNull Integer id, @NonNull String name) {
        if(id == null) {
            throw new NullPointerException("id");
        } else if(name == null) {
            throw new NullPointerException("name");
        } else {
            this.id = id;
            this.name = name;
        }
    }
}

@RequiredArgsConstructor(staticName = "of):

@RequiredArgsConstructor(staticName = "of")
public class TestBean {
    @NonNull private Integer id ;
    @NonNull private String name ;
    private int fa;
}

 生成对应的.class为        参数只为   未初始化的 final 字段和使用 @NonNull 标注

public class TestBean {
    @NonNull
    private Integer id;
    @NonNull
    private String name;
    private int fa;


    private TestBean(@NonNull Integer id, @NonNull String name) {
        if(id == null) {
            throw new NullPointerException("id");
        } else if(name == null) {
            throw new NullPointerException("name");
        } else {
            this.id = id;
            this.name = name;
        }
    }


    public static TestBean of(@NonNull Integer id, @NonNull String name) {
        return new TestBean(id, name);
    }
}
  @AllArgsConstructor      包含所有参数的构造器
@AllArgsConstructor(suppressConstructorProperties = true)
public class TestBean {
    @NonNull private Integer id ;
    @NonNull private String name ;
    private int fa;
}

  对应.class 文件为:   包含了所有参数

public class TestBean {
    @NonNull
    private Integer id;
    @NonNull
    private String name;
    private int fa;

    public TestBean(@NonNull Integer id, @NonNull String name, int fa) {
        if(id == null) {
            throw new NullPointerException("id");
        } else if(name == null) {
            throw new NullPointerException("name");
        } else {
            this.id = id;
            this.name = name;
            this.fa = fa;
        }
    }
}

@Data 包含了 @ToString、@EqualsAndHashCode、@Getter / @Setter和@RequiredArgsConstructor的功能

@Accessors  控制生成的set  get 方法     和@Data 或者@Setter @Getter搭配使用

   @Accessors(fluent = true, chain = true, prefix = "abc")

   fluent     Boolean类型值   默认为false。此字段主要为控制生成的getter和setter方法前面是否带get/set【false 带有】

   chain      boolean值,默认false。如果设置为true,setter返回的是此对象,方便链式调用方法  【true 是链式】

   prefix      参数的前缀  @Accessors(prefix = "abc") private String abcAge 当生成get/set方法时,会把此前缀去掉

   例如;

@Setter
@Getter
@Accessors(fluent = true, chain = true)
public class TestBean {
    @NonNull
    private Integer id;
    @NonNull
    private String name;
    // 使用@Accessors(prefix = "abc") 区分大小写
    @Accessors(prefix = "abc")
    private int abcFa;
}

   对应生成的.class 为:   函数不带set   链式调用且带有前缀的 去掉了前缀abc

public class TestBean {
    @NonNull
    private Integer id;
    @NonNull
    private String name;
    private int abcFa;

    public TestBean() {
    }

    public TestBean id(@NonNull Integer id) {
        if(id == null) {
            throw new NullPointerException("id");
        } else {
            this.id = id;
            return this;
        }
    }

    public TestBean name(@NonNull String name) {
        if(name == null) {
            throw new NullPointerException("name");
        } else {
            this.name = name;
            return this;
        }
    }

    public void setFa(int abcFa) {
        this.abcFa = abcFa;
    }

    @NonNull
    public Integer id() {
        return this.id;
    }

    @NonNull
    public String name() {
        return this.name;
    }

    public int getFa() {
        return this.abcFa;
    }
}

 注意:使用@Accessors(prefix = "abc")private int abcFa;    要修饰带有指定前缀的参数     并前缀与后参数名区分大小写

@Synchronized  修饰方法  给该方法加同步锁

 如

   @Synchronized
    private void initModel() {
        TestBean testBean = new TestBean();
        testBean.name("测试");
        Toast.makeText(this, testBean.name(), Toast.LENGTH_SHORT).show();
    }

对应的.class 为

public class MainActivity extends AppCompatActivity {
    private final Object $lock = new Object[0];

    public MainActivity() {
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(2131296283);
        this.initModel();
    }

    private void initModel() {
        Object var1 = this.$lock;
        synchronized(this.$lock) {
            TestBean testBean = new TestBean();
            testBean.name("测试");
            Toast.makeText(this, testBean.name(), 0).show();
        }
    }
}
 
 // 使用指定对象锁
    private final Object lock = new Object();
    @Synchronized("lock")
    private void initModel() {
        TestBean testBean = new TestBean();
        testBean.name("测试");
        Toast.makeText(this, testBean.name(), Toast.LENGTH_SHORT).show();
    }

   对应的.class

public class MainActivity extends AppCompatActivity {
    private final Object lock = new Object();

    public MainActivity() {
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(2131296283);
        this.initModel();
    }

    private void initModel() {
        Object var1 = this.lock;
        synchronized(this.lock) {
            TestBean testBean = new TestBean();
            testBean.name("测试");
            Toast.makeText(this, testBean.name(), 0).show();
        }
    }
}
8@Wither    提供修改final字段的方法   【实际上是判断newValue 是否和oldValue一样,,不一样重新new对象传新值,返回,达到修改final修饰值的目的】(貌似只能是修改int型)

例如:

public class TestBean {
    @Wither
    private final int  id;
    @Wither(AccessLevel.PROTECTED)
    private final int  name;

    public TestBean(int  name, int  id) {
        this.name = name;
        this.id = id;
    }
}

 生成对应的.class 为,  里边是用== 进行判断的

public class TestBean {
    private final int id;
    private final int name;

    public TestBean(int name, int id) {
        this.name = name;
        this.id = id;
    }

    public TestBean withId(int id) {
        return this.id == id?this:new TestBean(id, this.name);
    }

    protected TestBean withName(int name) {
        return this.name == name?this:new TestBean(this.id, name);
    }
}
     使用上为     实际返回了一个新对象
 TestBean testBean = new TestBean(1,2);
        testBean.withId(4);

   9 @Getter(onMethod = @_("新注解"))   注解里加注解   适用于结合数据库

    例如:

public class Test implements Serializable {
    private static final long serialVersionUID = -196412797757026250L;

    @Getter(onMethod = @_(@Column(name = "available")))
    @Setter
    private Integer available = 1;
}

  10 @Builder    创建一个静态内部类, 使用该类可以使用链式调用创建对象

@Builder
public class TestBean {
    private  int  id;
    private  int  name;
}

   对应的.class 为      通过构造链式获取实例

public class TestBean {
    private int id;
    private int name;

    TestBean(int id, int name) {
        this.id = id;
        this.name = name;
    }

    public static TestBean.TestBeanBuilder builder() {
        return new TestBean.TestBeanBuilder();
    }
     
    public static class TestBeanBuilder {
        private int id;
        private int name;

        TestBeanBuilder() {
        }

        public TestBean.TestBeanBuilder id(int id) {
            this.id = id;
            return this;
        }

        public TestBean.TestBeanBuilder name(int name) {
            this.name = name;
            return this;
        }

        public TestBean build() {
            return new TestBean(this.id, this.name);
        }

        public String toString() {
            return "TestBean.TestBeanBuilder(id=" + this.id + ", name=" + this.name + ")";
        }
    }
}

使用为:

TestBean testBean =TestBean.builder().id(2).name(1).build();

11 @Delegate   修饰集合list  set  map  都可以    生成相关的方法   判空  个数等

public class TestBean {
    private int id;
    private int name;
    //    private Set<String> strings = new HashSet<>();
    @Delegate
    private Map<String, Integer> map = new HashMap<>();
}

  对应的.class 文件为:   省略很多方法

public class TestBean {
    private int id;
    private int name;
    private Map<String, Integer> map = new HashMap();

    public TestBean() {
    }

    public int size() {
        return this.map.size();
    }

    public boolean isEmpty() {
        return this.map.isEmpty();
    }

    public boolean containsKey(Object arg0) {
        return this.map.containsKey(arg0);
    }

    public boolean containsValue(Object arg0) {
        return this.map.containsValue(arg0);
    }

    public Integer get(Object arg0) {
        return (Integer)this.map.get(arg0);
    }

    public Integer put(String arg0, Integer arg1) {
        return (Integer)this.map.put(arg0, arg1);
    }

    public Integer remove(Object arg0) {
        return (Integer)this.map.remove(arg0);
    }

    public void putAll(Map<? extends String, ? extends Integer> arg0) {
        this.map.putAll(arg0);
    }

    public void clear() {
        this.map.clear();
    }
    
    省略。。。。。。。

}
12 @NonNull

在方法或构造函数的参数上使用@NonNull,lombok将生成一个空值检查语句。【如果为null会抛出异常 ,方便找到哪里为空】

例如:

   private void initModel(@NonNull String params) {
        params.equals("1");
    }

生成对应的.class为:    为null  抛出哪里为null 的异常

 private void initModel(@NonNull String params) {
        if(params == null) {
            throw new NullPointerException("params");
        } else {
            params.equals("1");
        }
    }

13 @Cleanup    修饰io对象     自动释放io资源

 如:

public void example() throws IOException {
        @Cleanup InputStream in = new FileInputStream("2");
        @Cleanup OutputStream out = new FileOutputStream("2");
        byte[] b = new byte[10000];
        while (true) {
            int r = in.read(b);
            if (r == -1) break;
            out.write(b, 0, r);
        }
    }
 对应的.class 为:   省去自己在finally里回收资源
 public void example() throws IOException {
        FileInputStream in = new FileInputStream("2");
        try {
            FileOutputStream out = new FileOutputStream("2");

            try {
                byte[] b = new byte[10000];

                while(true) {
                    int r = in.read(b);
                    if(r == -1) {
                        return;
                    }

                    out.write(b, 0, r);
                }
            } finally {
                if(Collections.singletonList(out).get(0) != null) {
                    out.close();
                }

            }
        } finally {
            if(Collections.singletonList(in).get(0) != null) {
                in.close();
            }

        }
    }

14 @Value  功能和 @Data类似   都是生成 getter toString()、equals()和hashCode()    会把类和参数声明称final的

 如

  @Value
  @RequiredArgsConstructor(suppressConstructorProperties = true)
public class TestBean {
    private int id;
    private int name;
    private Map<String, Integer> map = new HashMap<>();
}

 对应的.class为   生成的代码比较长  直接上方法截图


15@SneakyThrows     只是伪造编译器。在JVM(类文件)级别上,不管您的方法的抛出子句,都可以抛出所有检查或不检查的异常   

  官方例子:修饰抛出异常的方法

@SneakyThrows
public void testSneakyThrows() {
    throw new IllegalAccessException();
}

 对应的.class为:

public void testSneakyThrows() {
    try {
        throw new IllegalAccessException();
    } catch (java.lang.Throwable $ex) {
        throw lombok.Lombok.sneakyThrow($ex);
    }
}

16@Getter(lazy=true)   缓存参数值(getter方法计算值需要大量CPU,或者值占用大量内存,第一次调用这个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;  
  }  
}  

  对应的.class为:

 public class GetterLazyExample {
  private final java.util.concurrent.AtomicReference<java.lang.Object> cached = new java.util.concurrent.AtomicReference<java.lang.Object>();
  
  public double[] getCached() {
    java.lang.Object value = this.cached.get();
    if (value == null) {
      synchronized(this.cached) {
        value = this.cached.get();
        if (value == null) {
          final double[] actualValue = expensive();
          value = actualValue == null ? this.cached : actualValue;
          this.cached.set(value);
        }
      }
    }
    return (double[])(value == this.cached ? null : value);
  }
  
  private double[] expensive() {
    double[] result = new double[1000000];
    for (int i = 0; i < result.length; i++) {
      result[i] = Math.asin(i);
    }
    return result;
  }
}
注意事项:  依赖 compile 'javax.annotation:javax.annotation-api:1.2'
    compile 'org.projectlombok:lombok:1.16.8'
在使用@Data  或者 @RequiredArgsConstructor and @AllArgsConstructor  有时会报

解决办法:

@AllArgsConstructor(suppressConstructorProperties = true) 或者

@RequiredArgsConstructor(suppressConstructorProperties = true)

LomBok原理分析:

接下来进行lombok能够工作的原理分析,以Oracle的javac编译工具为例。
自从Java 6起,javac就支持“JSR 269 Pluggable Annotation Processing API”规范,只要程序实现了该API,就能在javac运行的时候得到调用。
举例来说,现在有一个实现了"JSR 269 API"的程序A,那么使用javac编译源码的时候具体流程如下:
1)javac对源代码进行分析,生成一棵抽象语法树(AST)
2)运行过程中调用实现了"JSR 269 API"的A程序
3)此时A程序就可以完成它自己的逻辑,包括修改第一步骤得到的抽象语法树(AST)
4)javac使用修改后的抽象语法树(AST)生成字节码文件
详细的流程图如下:

 


   lombok本质上就是这样的一个实现了"JSR 269 API"的程序。在使用javac的过程中,它产生作用的具体流程如下:
1)javac对源代码进行分析,生成一棵抽象语法树(AST)
2)运行过程中调用实现了"JSR 269 API"的lombok程序
3)此时lombok就对第一步骤得到的AST进行处理,找到@Data注解所在类对应的语法树(AST),然后修改该语法树(AST),增加getter和setter方法定义的相应树节点
4)javac使用修改后的抽象语法树(AST)生成字节码文件

猜你喜欢

转载自blog.csdn.net/xuwb123xuwb/article/details/80252491