Lombok

  • Lombok资源
  • IntelliJ IDEA安装Lombok
  • Lombok特性
    • val
    • NonNull
    • Cleanup
    • Getter and Setter
    • ToString
    • Builder

Lombok资源

Lombok官网:

  • Lombok官网

Lombox下载地址:

  • Lombox下载

GitHub官方账号:

  • Lombok官方账号

我的码云Lombok测试源码:

  • Lombok测试源码

Lombok官方接口文档:

  • Lombok接口文档

IntelliJ IDEA安装Lombok

  在File > Settings > Plugins点击Browse repositories,搜索Lombok插件,点击Install plugin,安装完后重启即可,如下所示即为安装成功后的界面。

Lombok_第1张图片

Lombok特性

val

  您可以使用val作为本地变量声明的类型,而不是实际地编写类型。当您这样做时,类型将从初始化器表达式中推断出来。局部变量也将被最终确定。这个特性只适用于局部变量,只针对每个循环,而不是在字段上。需要初始化器表达式。

  val实际上是一种“类型”,在Lombok包中作为真正的类存在。您必须将其导入到val中才能工作(或者使用Lombok.val的类型)。在局部变量声明中存在这种类型,会触发final关键字的添加,以及复制“伪”val类型的初始化表达式的类型。

  警告:这个特性目前还没有在NetBeans中使用。

  val接口测试源码如下:

package com.lyc.lombok;

import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.junit.Assert;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

@Slf4j
public class ValExample {

    /**
     * 将"Hello,World!"中的大写字母转换成小写字母"hello,world!"
     */
    @Test
    public void testVal(){
        //初始化相关数据
        val example = new ArrayList();
        example.add("Hello,World!");
        //输出
        example.forEach((String s) -> log.info(s.toLowerCase()));
        //验证
        example.forEach((String s) -> Assert.assertEquals("hello,world!",s.toLowerCase()));
    }

    @Test
    public void testVal2(){
        //初始化相关数据
        val map = new HashMap<Integer, String>();
        val list = Arrays.asList("0:zero","5:five");
        val list2 = new ArrayList<String>();
        map.put(0, "zero");
        map.put(5, "five");
        map.forEach((k,v) -> {
            list2.add(k + ":" + v);
        });
        //输出
        map.forEach((k,v) -> log.info(k + ":" +v));
        //验证
        Assert.assertEquals(list,list2);
    }

}

分析

  上述第一个方法testVal()中实现的功能是用Lombok中的val创建一个ArrayList容器,我们将该容器中首字母大写的字符串“Hello,World!”转换成全部小写的“hello,world!”,转换成功后,在控制台中输出的内容如下:

2018-01-09 15:31:15.320 [main] INFO  com.lyc.lombok.ValTest - hello,world!

  上述第二个方法testVal2()实现的功能是用Lombok中的val创建一个HashMap容器,在容器中我们放入相应的元素,然后我们再将其打印到控制台中,输出的结果如下:

2018-01-09 15:34:07.955 [main] INFO  com.lyc.lombok.ValTest - 0:zero
2018-01-09 15:34:07.958 [main] INFO  com.lyc.lombok.ValTest - 5:five

@NonNull

  您可以在方法或构造函数的参数上使用@NonNull,以使lombok为您生成一个空值检查语句。

  Lombok总是在字段中查找被标记为@NonNull的注解,为您生成一个完整的方法或构造函数并处理相应的null-check,例如@Data。但是,现在使用lombok自己的@lombok.NonNull在一个参数中的结果就是相当于在您自己的方法或构造函数中插入了null-check语句。

  null-check看起来就像if (param == null) throw new NullPointerException("param");;并且会被插入到你的方法的最顶端。对于构造函数,在任何显式的this()super()调用之后,将立即插入null-check

  如果在顶部已经出现了null-check ,那么就不会生成额外的null-check

  @NonNull接口测试源码如下:

package com.lyc.lombok;

import com.lyc.entity.Hello;
import com.lyc.entity.Person;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

@Slf4j
public class NonNullTest extends Hello{

    private String name;

    /**
     * 将会抛出下面异常:
     * java.lang.Exception: Method testNonNull should have no parameters
     * @param person
     */
    @Test
    public void testNonNull(@NonNull Person person){
        this.name = person.getName();
    }

}

分析

  上述程序是用Lombok中的@NonNull注解检查参数的空指针异常,如果存在空指针异常,那么在控制台中打印出相应的异常。

  由于testNonNull()中的方法参数并没有被初始化,然后就直接拿来使用了,因而会报下列的空指针异常信息。

java.lang.Exception: Method testNonNull should have no parameters

@Cleanup

  您可以使用@Cleanup来确保在代码执行路径退出当前范围之前,将自动清除给定的资源。您可以通过使用@Cleanup注解来注释任何本地变量声明,如下所做:

@Cleanup InputStream in = new FileInputStream("some/file");

  因此,在您所处的范围的末尾,将调用in.close()方法。这个调用可以通过一个try/finally构造来运行。请看下面的例子,看看它是如何工作的。

  如果您想要清除的对象类型没有close()方法,但是有一些其他的无参数方法,您可以指定该方法的名称:

@Cleanup("dispose") org.eclipse.swt.widgets.CoolBar bar = new CoolBar(parent, 0);

  默认情况下,清理方法被假定为close()。一个需要一个或多个参数的清理方法不能通过@Cleanup来调用。

  @Cleanup接口测试源码如下:

package com.lyc.lombok;

import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class CleanupTest {

    /**
     * 文件输入流,输出流在使用后都没有被关闭
     * @return
     * @throws IOException
     */
    public List test() throws IOException {
        //aa.properties文件资源路径
        String aaResourcePath = CleanupTest.class.getClassLoader().getResource("aa.properties").getPath();
        //bb.properties文件资源路径
        String bbResourcePath = CleanupTest.class.getClassLoader().getResource("bb.properties").getPath();
        //创建list容器
        List list = new ArrayList();
        //打印aa.properties文件资源路径
        log.info("文件路径:" + aaResourcePath);
        //打印bb.properties文件资源路径
        log.info("文件路径:" + bbResourcePath);
        //aa.properties文件输入流
        InputStream in = new FileInputStream(aaResourcePath);
        //bb.properties文件输出流
        OutputStream out = new FileOutputStream(bbResourcePath);
        byte[] b = new byte[10000];
        //将aa.properties文件中的“aa.test=test”输入到bb.properties中去
        while (true) {
            int r = in.read(b);
            if (r == -1) break;
            out.write(b, 0, r);
        }
        list.add(in);
        list.add(out);
        return list;
    }

    /**
     * 文件输入流,输出流在使用后都被关闭
     * @return
     * @throws IOException
     */
    public List test2() throws IOException {
        //aa.properties文件资源路径
        String aaResourcePath = CleanupTest.class.getClassLoader().getResource("aa.properties").getPath();
        //bb.properties文件资源路径
        String bbResourcePath = CleanupTest.class.getClassLoader().getResource("bb.properties").getPath();
        //创建list容器
        List list = new ArrayList();
        //打印aa.properties文件资源路径
        log.info("文件路径:" + aaResourcePath);
        //打印bb.properties文件资源路径
        log.info("文件路径:" + bbResourcePath);
        //aa.properties文件输入流
        @Cleanup InputStream in = new FileInputStream(aaResourcePath);
        //bb.properties文件输出流
        @Cleanup OutputStream out = new FileOutputStream(bbResourcePath);
        byte[] b = new byte[10000];
        //将aa.properties文件中的“aa.test=test”输入到bb.properties中去
        while (true) {
            int r = in.read(b);
            if (r == -1) break;
            out.write(b, 0, r);
        }
        list.add(in);
        list.add(out);
        return list;
    }


    /**
     * 这里测试的是没有关闭文件输入流,输出流的情况,所以说这里就不会报错。
     * @throws IOException
     */
    @Test
    public void testCleanup() throws IOException {
        log.info("这里是testCleanup()方法:");
        List list = test();
        InputStream in = (InputStream) list.get(0);
        OutputStream out = (OutputStream) list.get(1);
        log.info("---------------------------------------------------");
        log.info("当我们看到这段信息时,这就说明输入文件流与输出文件流均没关闭");
        log.info("输入文件流:" + in.available());
        log.info("输入文件流:" + out.toString());
        log.info("---------------------------------------------------");
    }

    /**
     * 这里测试的是关闭文件输入流与输出流的情况,所以说这里就会报错。
     * @throws IOException
     */
    @Test
    public void testCleanup2() throws IOException {
        log.info("这里是testCleanup2()方法:");
        List list = test2();
        InputStream in = (InputStream) list.get(0);
        OutputStream out = (OutputStream) list.get(1);
        log.info("---------------------------------------------------");
        log.info("当我们看到这段信息时,这就说明输入文件流与输出文件流均没关闭");
        log.info("输入文件流:" + in.available());
        log.info("输入文件流:" + out.toString());
        log.info("---------------------------------------------------");
    }

}

分析:

  上面的代码看上去有些多,其实现的功能就是将资源文件aa.properties中的aa.test=test字符串输入到空资源文件bb.properties中去,最后再返回装有输入与输出流的list容器。
  我们在testCleanup()中测试的是没有关闭输入与输出流的情况,由于文件流没有被关闭,因而后面再调用in.available()方法时,这里是不会抛出异常的,因而输出结果如下:

2018-01-09 15:19:36.664 [main] INFO  com.lyc.lombok.CleanupTest - 这里是testCleanup()方法:
2018-01-09 15:19:36.668 [main] INFO  com.lyc.lombok.CleanupTest - 文件路径:/F:/Test2/lombok/target/classes/aa.properties
2018-01-09 15:19:36.668 [main] INFO  com.lyc.lombok.CleanupTest - 文件路径:/F:/Test2/lombok/target/classes/bb.properties
2018-01-09 15:19:36.669 [main] INFO  com.lyc.lombok.CleanupTest - ---------------------------------------------------
2018-01-09 15:19:36.669 [main] INFO  com.lyc.lombok.CleanupTest - 当我们看到这段信息时,这就说明输入文件流与输出文件流均没关闭
2018-01-09 15:19:36.669 [main] INFO  com.lyc.lombok.CleanupTest - 输入文件流:0
2018-01-09 15:19:36.669 [main] INFO  com.lyc.lombok.CleanupTest - 输入文件流:java.io.FileOutputStream@b97c004
2018-01-09 15:19:36.669 [main] INFO  com.lyc.lombok.CleanupTest - ---------------------------------------------------

  当我们在调用testCleanup2()中的方法时,由于test2()中引入了@Cleanup注解,因而文件流早已被关闭,我们在testCleanup2()中调用被关闭的文件流的in.available()方法时,此时就会抛出相应的异常,异常如下:

2018-01-09 15:24:28.184 [main] INFO  com.lyc.lombok.CleanupTest - 这里是testCleanup2()方法:
2018-01-09 15:24:28.189 [main] INFO  com.lyc.lombok.CleanupTest - 文件路径:/F:/Test2/lombok/target/classes/aa.properties
2018-01-09 15:24:28.189 [main] INFO  com.lyc.lombok.CleanupTest - 文件路径:/F:/Test2/lombok/target/classes/bb.properties
2018-01-09 15:24:28.190 [main] INFO  com.lyc.lombok.CleanupTest - ---------------------------------------------------
2018-01-09 15:24:28.190 [main] INFO  com.lyc.lombok.CleanupTest - 当我们看到这段信息时,这就说明输入文件流与输出文件流均没关闭

java.io.IOException: Stream Closed

    at java.io.FileInputStream.available(Native Method)
    at com.lyc.lombok.CleanupTest.testCleanup2(CleanupTest.java:108)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    ...

@Getter and @Setter

  这个方法比较简单,而且是在Java Web中最长用到的方法,那就是直接在类上面添加相应的注解即可,代码如下。

  首先创建名为cat的实体类

package com.lyc.entity;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Cat {

    private String name;

}

  然后再创建相应的测试源码:

package com.lyc.lombok;

import com.lyc.entity.Cat;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;

@Slf4j
public class GetterAndSetterTest {

    @Test
    public void testGetterAndSetter(){
        Cat cat = new Cat();
        //先用@Setter方式为其赋值
        cat.setName("波斯猫");
        //再用@Getter方式取值
        log.info(cat.getName());
        Assert.assertEquals("波斯猫",cat.getName());
    }
}

分析

  上述程序实现的功能是在testGetterAndSetter()这里写代码片方法中用Lombok中的@Setter方法为Catname字段赋值,然后再用Lombok中的@Getter方法将其取出来。

@ToString

  这个方法比较简单,而且是在Java Web中最长用到的方法之一,那就是直接在类上面添加相应的注解即可,代码如下。

  先创建ToStringExample类:

package com.lyc.entity;

import lombok.ToString;

@ToString
public class ToStringExample {

    private String name = "This Is ToString Method.";

}

  再创建ToStringTest测试代码:

package com.lyc.entity;

import lombok.ToString;

@ToString
public class ToStringExample {

    private String name = "This Is ToString Method.";

}

分析:

  上述程序实现的功能是在ToStringExample中添加@ToString注解,在ToStringTest中进行测试,目的就是为了检验在ToStringExample中添加@ToString注解是否能够将name字段转换为ToString输出。

@Builder

  @builder注解为您的类生成复杂的构建api,让您自动生成代码,使您的类能够实例化,例如:

Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();

  这个方法比较简单,而且是在Java Web中最长用到的方法之一,那就是直接在类上面添加相应的注解即可,代码如下。

  首先创建BuilderExample类:

package com.lyc.entity;

import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class BuilderExample {

    private String name;
    private int age;

}

  然后再创建BuilderTest代码测试类:

package com.lyc.lombok;

import com.lyc.entity.BuilderExample;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;

@Slf4j
public class BuilderTest {

    @Test
    public void test(){
        BuilderExample builderExample = BuilderExample.builder()
                .age(21)
                .name("zhangsan").build();
        log.info("姓名:" + builderExample.getName() + ",年龄:" + builderExample.getAge());
        Assert.assertEquals("姓名:zhangsan,年龄:21","姓名:" + builderExample.getName() + ",年龄:" + builderExample.getAge());
    }

}

分析:

  上述程序实现的功能是在BuilderExample类中添加@Builder注解,当然这里还得再添加一个@Getter,否则后面我们对实体类中的赋值操作将无法获取有效值,之后我们在BuilderTest类中先用BuilderExample.builder()方法生成一个构建器,之后就是采用链式调用,直接点出来后面的参数,然后赋值,最后调用build()方法完成构建操作。这样我们在实体类中的赋值操作就已经成功完成了。

  由于后面的注解基本上用法和上面的相似,并且由于Lombok本身用法就挺简单的,因此我就不一一再重复编写了,详细的可以去看上面我列出的官方文档信息。

你可能感兴趣的:(Java)