Java进阶教程:使用Lombok提升开发效率

Java进阶教程:使用Lombok提升开发效率

Lombok

  Lombok是一种Java™实用工具,可用来帮助开发人员消除Java的冗长代码,尤其是对于简单的Java对象(POJO)。它通过注释实现这一目的。通过在开发环境中实现Lombok,开发人员可以节省构建诸如hashCode()和equals()这样的方法以及以往用来分类各种accessor和mutator的大量时间。

Lombok安装

  下面是通过Maven进行安装的,也可以在官网下载Jar包。

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.16.12</version>
</dependency>

插件安装

  Lombok通过编译时根据注解插入一些相关代码,来实现其简化开发的目的。所以,在开发时,诸如Setter/Getter等都是无法进行代码提示的。IDEA推荐使用Lombok插件:

  

 

示例

@Val和@Var

  前者定义常量,后者定义局部变量,其类型可以自动推测,不需要明确指出。

    public static void varAndVal(var c){ //[X]不可用于形参
        val a = 10; //[√]定义一个常量,其类型可自动推测
        var b = 10; //[√]定义一个变量,其类型可自动推测
        a++;         //[X]常量无法被修改,此处报错!
        b++;         //[√]此处为Int类型变量,可以进行自增操作
        b = "String";//[X]仍然遵循强类型规则,不可修改类型
    }

 

@Cleanup和@SneakyThrows

  使用Cleanup以确保在代码执行路径退出当前作用域之前自动清除给定资源

    @SneakyThrows
    public static void cleanUp(){
        @Cleanup OutputStreamWriter writer = new OutputStreamWriter(System.out);
        writer.write("Hello World");
    }

  如果我们反编译该代码,Lombok自动为我们做了资源清理以及异常抛出

public static void cleanUp() {
        try {
            OutputStreamWriter writer = new OutputStreamWriter(System.out);

            try {
                writer.write("Hello World");
            } finally {
                if (Collections.singletonList(writer).get(0) != null) {
                    writer.close();
                }

            }

        } catch (Throwable var5) {
            throw var5;
        }
    }

   同时我们还用了一个注解@SneakyThrows,他可以帮助我们抛出已检查的异常而开发时不需要在方法的throws子句中实际声明

 

@Getter和@Setter

  解放双手,不用再写访问器了!

class Hello{
    @Getter
    @Setter
    private int a;

    public static void main(String[] args) {
       Hello a = new Hello();
        a.setA(10); //Setter
        System.out.println(a.getA()); //Getter
    }
}

  

@NonNull

  给方法参数增加这个注解会自动在方法内执行前对该参数进行是否为空的校验,如果为空,则抛出NPE(NullPointerException)

    //不会打印10
    public static void nonNull(@NonNull HashSet a){
        System.out.println(10);
        System.out.println(a.size());
    }

    //打印10后才会抛出异常,所以方法可能错误执行一部分
    public static void notNull(HashSet a){
        System.out.println(10);
        System.out.println(a.size());
    }

  加上这个注解后,实际代码如下:

    public static int nonNull(@NonNull HashSet a) {
        if (a == null) {
            throw new NullPointerException("a");
        } else {
            System.out.println(10);
            System.out.println(a.size());
            return 10;
        }
    }

 

@ToString

  为使用该注解的类生成一个toString方法,默认的toString格式为:ClassName(fieldName= fieleValue ,fieldName1=fieleValue)。

@ToString(includeFieldNames = true,exclude = {"a"})
class Hello{
    @Getter
    @Setter
    private int a =10;
    private double b =20.19;
    private String c = "hello";

    public static void main(String[] args) {
        Hello a = new Hello();
        System.out.println(a);
        //RESULT:Hello(b=20.19, c=hello)
    }
}

  

@EqualsAndHashCode

  为使用该注解的类自动生成equals和hashCode方法。

@EqualsAndHashCode
class Hello{
    private int a =10;
    private double b =20.19;
    private String c = "hello";
}

  加注解很简单,但实际上Lombok帮我们重写了equals和hashCode方法,可见其equals是比较了字段的值以及是否为null而得出的。

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Hello)) {
            return false;
        } else {
            Hello other = (Hello)o;
            if (!other.canEqual(this)) {
                return false;
            } else if (this.getA() != other.getA()) {
                return false;
            } else if (Double.compare(this.b, other.b) != 0) {
                return false;
            } else {
                Object this$c = this.c;
                Object other$c = other.c;
                if (this$c == null) {
                    if (other$c == null) {
                        return true;
                    }
                } else if (this$c.equals(other$c)) {
                    return true;
                }

                return false;
            }
        }
    }

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

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        int result = result * 59 + this.getA();
        long $b = Double.doubleToLongBits(this.b);
        result = result * 59 + (int)($b >>> 32 ^ $b);
        Object $c = this.c;
        result = result * 59 + ($c == null ? 43 : $c.hashCode());
        return result;
    }

 

@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsContructor

  • @NoArgsConstructor : 生成一个无参数的构造方法
  • @AllArgsContructor: 生成一个包含所有变量的构造方法
  • @RequiredArgsConstructor: 会生成一个包含常量和标识了NotNull的变量的构造方法。生成的构造方法是私有的private。

  对于RequiredArgsConstructor来说,它提供了一种新的构造思路,即通过静态方法,赋予其有意义的方法名,来构造对象。

    private Hello(@NonNull double b, @NonNull String c) {
        if (c == null) {
            throw new NullPointerException("c");
        } else {
            this.b = b;
            this.c = c;
        }
    }

    public static Hello buildByBAndC(@NonNull double b, @NonNull String c) {
        return new Hello(b, c);
    }

 

@Data

  @Data注解作用比较全,其包含注解的集合@ToString@EqualsAndHashCode,所有字段的@Getter和所有非final字段的@Setter@RequiredArgsConstructor

 

@Builder

  Builder注解可以快速实现构建者模式,即通过函数来赋值字段,以及构建最终对象

@ToString
@Builder
class Hello{
    private int a;
    private double b;
    private String c;

    public static void main(String[] args) {
        Hello a = Hello.builder().a(11).b(12).c("hi").build();
        System.out.println(a);
        //RESULT:Hello(a=11, b=12.0, c=hi)
    }
}

  

@Synchronized

  多线程开发时,锁定this或你自己的类对象可能会产生不幸的副作用,因为不受你控制的其他代码也可以锁定这些对象,这可能会导致竞争条件和其他讨厌的线程相关错误。

  @Synchronized注解类似Java中的Synchronized 关键字,但是可以隐藏同步锁,Lombok会自动去创建对象锁。

    @Synchronized
    public static void  synchDemo1(){
        System.out.println("World");
    }

  它实际编译的代码如下

    private static final Object $LOCK = new Object[0];

    public static void synchDemo1() {
        synchronized($LOCK) {
            System.out.println("World");
        }
    }

 

Lombok原理

  Lombok这款插件依靠可插件化的Java自定义注解处理API(JSR 269: Pluggable Annotation Processing API)来实现在Javac编译阶段利用“Annotation Processor”对自定义的注解进行预处理后生成真正在JVM上面执行的“Class文件”
  
  从上面的Lombok执行的流程图中可以看出,在Javac 解析成AST抽象语法树之后, Lombok 根据自己编写的注解处理器,动态地修改 AST,增加Lombok自定义注解所需要生成的代码,最终通过分析生成JVM可执行的字节码Class文件。使用Annotation Processing自定义注解是在编译阶段进行修改,而JDK的反射技术是在运行时动态修改,两者相比,反射虽然更加灵活一些但是带来的性能损耗更加大

参考链接

 

posted @ 2019-08-28 14:13  子烁爱学习  阅读(547)  评论(0编辑  收藏  举报