lombok-精简你的Java代码

2018/04/11 java lombok jdk10

版权声明:可以任意转载,转载时请标明文章原始出处-xjtushilei和作者信息:石磊

前言

jdk10都已经支持var了,其实在很久之前lombok都已经基于Annotation Processing 技术(直接操纵抽象语法树AST,根据需要添加新节点)实现了更丰富的功能,使用起来还是很舒服的,但是由于其某些弊端,并没有流行起来。个人认为在vo特别复杂的情况下,代码量很大,修改很频繁下,使用lombok也不为过。如果在项目里未和队友商量的情况下,大量使用这种黑科技,就要被打死了。

原理

先来一波原理

自从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)生成字节码文件

IDEA使用准备

  1. 下载lombok插件,并安装
  2. 打开设置里默认关闭的Annotation Processing选项,方法如下图:

    如果不打开改选项,则编译期会发生错误:

使用

val 和 var 动态类型

val和var的区别为:是否为final的。val是final的,但是var就是正常的变量。

    //val
    val example =new ArrayList<String>();
    example.add("HelloWorld");
    val foo = example.get(0);
    System.out.println(foo.toLowerCase());
    //val
    val map = new HashMap<Integer, String>();
    map.put(0, "zero");
    map.put(5, "five");
    for (val entry : map.entrySet()) {
        System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());
    }

@NonNull 空指针变量

    //@NonNull
    class TestNull{
        public void println(@NonNull String str){
            System.out.println(str);
        }
    }
    new TestNull().println("test pass");
    new TestNull().println(null);

其功能相当于:

if (str == null) {
      throw new NullPointerException("str");
}

@Cleanup 资源自动关闭

其实jdk7中已经实现了相关语法,这里提供了另一个语法。

首先jdk7里的 try-with-resource ,跟python里的语法差不多,都是自动关闭资源。有兴趣的可以自己查看。这里仅仅讲一下 lombok的实现。

        // @Cleanup
        @Cleanup OutputStream out = new FileOutputStream(new File("test.txt"));
        out.write("HelloWorld!".getBytes());

相当于非JDK7的特殊语法情况下,最普通的处理方式:

    OutputStream out = new FileOutputStream(new File("test.txt"));
    try {
    out.write("HelloWorld!".getBytes());
    } finally {
    if (out != null) {
      out.close();
    }
    }

@Getter @Setter

这个很好理解,直接用就好啦。IDEA的快捷键的效果跟这个一样,会更朴实好用一些。

    //@Getter @Setter
    class TestGetterSetter {
        @Getter
        @Setter
        private int age = 10;
    }
    val t = new TestGetterSetter();
    t.setAge(25);
    System.out.println(t.getAge());

@ToString

实现了 toString(),很好理解。

需要特别解释一些注释:

  • includeFieldNames 是否显示字段名字
  • exclude 排除哪些字段
  • callSuper 是否将父类的成员加入到toString()
  • of 跟 exclude 相对应,显示的增加自己想要显示的字段
    //@ToString
    @ToString(exclude="id",includeFieldNames=false)
    class ToStringExample {
        private static final int STATIC_VAR = 10;
        private String name="名字";
        private String[] tags={"1","2","3"};
        private int id=1;
    }
    System.out.println(new ToStringExample());

EqualsAndHashCode

和toString的注释很相似,也是:

  • exclude 排除哪些字段
  • callSuper 是否将父类的成员加入到EqualsAndHashCode
  • of 跟 exclude 相对应,显示的增加自己想要EqualsAndHashCode的字段
    //EqualsAndHashCode
    @EqualsAndHashCode(exclude={"id"})
    class EqualsAndHashCodeExample {
        private String name;
        private int count;
        private int id;
        public EqualsAndHashCodeExample(String name, int count, int id) {
            this.name = name;
            this.count = count;
            this.id = id;
        }
    }
    val o1 = new EqualsAndHashCodeExample("name1", 12, 15);
    val o2 = new EqualsAndHashCodeExample("name2", 12, 12);
    val o3 = new EqualsAndHashCodeExample("name1", 12, 16);
    System.out.println(o1.equals(o2));
    System.out.println(o2.equals(o3));
    System.out.println(o1.equals(o3));

构造函数

主要有三种, @NoArgsConstructor , @RequiredArgsConstructo , @AllArgsConstructor

其中主要解释一下sstaticName="of",效果相当于:

     public static ConstructorExample of(int x, int y) {
        return new ConstructorExample(int x, int y);
      }

使用示例:

    //AllArgsConstructor
    @NoArgsConstructor
    @RequiredArgsConstructor(staticName = "of")
    @AllArgsConstructor(staticName = "of", access = AccessLevel.PROTECTED)
    class ConstructorExample {
        private int x, y;
    }
    val c1 = new ConstructorExample();
    val c2 = new ConstructorExample(1, 2);
    val c3 = ConstructorExample.of(1, 2);

@Data 五合一

A shortcut for @ToString, @EqualsAndHashCode, @Getter on all fields, @Setter on all non-final fields, and @RequiredArgsConstructor!

@Value 四合一

与@Data相对应的@Value, 两个annotation的主要区别就是如果变量不加@NonFinal ,@Value会给所有的弄成final的。当然如果是final的话,就没有set方法了。

@Builder

这个很好用!!builder模式用的很舒服。

    @Builder
     public class Example {
            private int foo;
            private final String bar;
     }

    //构造一个实例,属性不需要单独set
    Example.builder().foo(1).bar(“test”).build()

log

@CommonsLog Creates

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

@JBossLog Creates

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

@Log Creates

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

@Log4j Creates

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

@Log4j2 Creates

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

@Slf4j Creates

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

@XSlf4j Creates

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

举例:

@Log4j
public class LogExample {

  public static void main(String... args) {
    log.error("Something's wrong here");
  }
}

更多

请前去官网

参考

  • 官网 https://projectlombok.org/
  • lombok的使用和原理 https://blog.csdn.net/dslztx/article/details/46715803

Search

    Post Directory