欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

优雅的Java工具库Lombok

程序员文章站 2023-01-13 13:47:50
优雅的Java工具库Lombok 最近在公司的项目中看到了对于Lombok的应用,通过@Data注解标注POJO,省略了大量的getter/setter代码,原先冗长的POJO在瘦身之后直接变得干净、清爽,程序员再也不需要去关注那些长长的方法,只需要集中注意力于字段field之中 Lombok简介 ......

优雅的java工具库lombok

最近在公司的项目中看到了对于lombok的应用,通过@data注解标注pojo,省略了大量的getter/setter代码,原先冗长的pojo在瘦身之后直接变得干净、清爽,程序员再也不需要去关注那些长长的方法,只需要集中注意力于字段field之中

lombok简介

lombok是一个非常实用的java工具库,有效地简化java代码的冗长。它通过注解如@data可以直接为java bean在编译期动态地生成字段的getter/setter方法,使用注解@noargsconstructor 和@allargsconstructor 为java bean添加无参构造器和有参构造器,甚至可以在java代码中使用val和var声明一个动态变量,而无需再指定具体的变量类型,区别只是val声明的变量为final。lombok还提供了delombok供生成javadoc,delombok在运行时会将注解@data转换成getter/setter方法,然后移除@data注解,如果哪天不再需要lombok,也只需要简单运行delombok即可。lombok的构建支持maven和gradle,同时eclipse、myeclipse和idea等主流ide也都和lombok兼容,所以可以放心大胆地使用lombok,不用担心ide的编译检查问题。

lombok栗子

eclipse安装lombok支持

官网lombok https://projectlombok.org/download 下载jar包或者通过构建工具maven,gradle下载jar包

双击jar包,jar包内的安装器会自动运行寻找eclipse

优雅的Java工具库Lombok

点击【install/update】

优雅的Java工具库Lombok

引入lombok依赖

    <dependency>
        <groupid>org.projectlombok</groupid>
        <artifactid>lombok</artifactid>
        <version>1.18.2</version>
        <scope>provided</scope>
    </dependency>

lombok注解使用

lombok的注解分为稳定版本和试验版本,这里主要介绍稳定版本,因为试验版本的支持目前和ide不是很好

@getter/@setter注解

@getter/@setter注解的作用就是为字段添加getter/setter方法,可标注在类上,也可标注在字段上。标注在类上表示所有的非静态(no-static)字段都会生成相应的getter/setter方法,标注在字段上表示只为这个字段生成,且会覆盖标注在类上的注解。可设置访问级别,默认为public。@setter不可以标注final字段

@getter@setter
public class setterexample {
    
    @getter(value=accesslevel.private)@setter
    private string name;
    
    //onmethod=@__({@annotationshere})
    @setter(onmethod=@__({@deprecated}))
    private string age;
    
    //onparam=@__({@annotationshere})
    @setter(onparam=@__({}))
    private string sex;
    
    public static void main(string[] args) {
        setterexample se = new setterexample();
        se.setname("zhangsan");
        se.setage("16");
        system.out.println(se.getage());
        system.out.println(se.getname());
    }
}

lombok提供了onx的试验属性,分别为:onmethod, onparam, onconstructor,用于向生成的方法,构造器,参数添加注解

反编译后结果

优雅的Java工具库Lombok

@nonnull注解

@nonnull注解标注方法和构造器的参数,如果参数为null,则会抛出空指针异常,不需要在代码中进行null检测

public class nonnullexample {
    
    @getter
    private string name;
    
    public nonnullexample(@nonnull string name){
        this.name = name;
    }
    
    public static void main(string[] args){
        string name = null;
        nonnullexample nne = new nonnullexample(name);
        system.out.println(nne.getname());
    }
}

@tostring注解

@tostring注解生成tostring()方法

@tostring
public class tostringexample {

    @tostring.exclude
    private string name;
    
    @tostring.include
    private string age;
    
    private string sex;
    
    public static void main(string[] args) {
        tostringexample tse = new tostringexample();
        system.out.println(tse.tostring());
    }
}

属性includefieldnames,默认为true,包含属性值

属性callsuper,默认为false,调用父类实现

属性onlyexplicitlyincluded,默认为false,仅包含明确包含的属性

@tostring.exclude 标注属性值不包含在tostring()方法中

@tostring.include标注属性值包含在tostring()方法中

@equalsandhashcode

@equalsandhashcode注解生成equals()和hashcode()方法,注解的属性和@tostring类似

@equalsandhashcode
public class equalsandhashcodeexample {

    private string name;
    private string age;
    private string sex;
    
    public static void main(string[] args) {
        equalsandhashcodeexample ehe1 = new equalsandhashcodeexample();
        equalsandhashcodeexample ehe2 = new equalsandhashcodeexample();
        system.out.println(ehe1.equals(ehe2));
        system.out.println(ehe1.hashcode());
        system.out.println(ehe2.hashcode());
    }
}

@noargsconstructor@requiredargsconstructor@allargsconstructor

@noargsconstructor : 生成一个无参数的构造方法

@noargsconstructor(force=true, staticname="newinstance")
public class noargsconstructorexample {

    //包含的final字段如果没有初始化,需要加上force=true强制初始化,否则编译错误
    private final string name;
    
    //不会进行null检查
    @nonnull
    @getter
    private string age;
    
    private string sex;
    
    public static void main(string[] args) {
        noargsconstructorexample nace1 = new noargsconstructorexample();
        system.out.println(nace1.getage());
        noargsconstructorexample nace2 = noargsconstructorexample.newinstance();
        system.out.println(nace2.getage());
    }
}

@requiredargsconstructor:会生成一个包含常量,和标识了notnull的变量 的构造方法。

@requiredargsconstructor(staticname="newinstance")
public class requiredargsconstructorexample {

    private final string name;
    
    @nonnull
    @getter
    private string age;
    
    private string sex;
    
    public static void main(string[] args) {
        requiredargsconstructorexample race1 = new requiredargsconstructorexample("lisi", "18");
        system.out.println(race1.getage());
        requiredargsconstructorexample race2 = requiredargsconstructorexample.newinstance("zhangsan", "16");
        system.out.println(race2.getage());
    }
}

@allargsconstructor:会生成一个包含所有变量,同时如果变量使用了notnull annotation , 会进行是否为空的校验

@allargsconstructor(staticname="newinstance")
public class allargsconstructorexample {

    private final string name;
    
    @nonnull
    @getter
    private string age;
    
    private string sex;
    public static void main(string[] args) {
        allargsconstructorexample aace1 = new allargsconstructorexample("zhangsan", "18", "female");
        system.out.println(aace1.getage());
        allargsconstructorexample aace2 = allargsconstructorexample.newinstance("lisi", "16", "male");
        system.out.println(aace2.getage());
    }
}

注意:三个注解生成的构造器都可以指定访问权限,同时也可以提供一个静态方法来供调用。三个注解的区别在于对final和@nonnull字段的处理不同

另外关于staticname属性,lombok源码注释如下:

if set, the generated constructor will be private, and an additional static 'constructor' is generated with the same argument list that wraps the real constructor.

很明显三个注解都是可以使用构造器直接创建对象的,也可以使用静态方法创建对象,不知道这段注释是什么意思???

@data注解

等同于@tostring, @equalsandhashcode, @getter, @setter和@requiredargsconstructor一起使用

@value

@value注解为不可变类型的@data,是@data的一个变种。它标注的类和字段都会被声明为final

@builder注解

@builder注解为类生成builder api以供调用。builder是一种解决包含数量巨大且繁杂的字段的类的一种构建方式。

假如一个类有几十个字段,那么该如何设计这个类呢?

方法一:将几十个字段都添加在构造函数中。简单粗暴,而且在构造函数中为字段初始化也能够保证对象能够正确创建。缺点就是几十个参数只会导致你在创建对象时记错参数的位置,导致不必要的麻烦。

方法二:依赖注入。spring的核心功能之一就是依赖注入,借助这种思想,我们通过无参构造创建一个对象,然后通过setter方法设置必需的属性。这种方式可以根据需求初始化相关属性,且逻辑清晰,但也会造成代码繁琐,需要调用多次setter方法。

方法三:builder模式。建造者模式的思想就是将一个大的类的构建分为几部分创建,从而简化创建的复杂性。

@builder
public class builderexample {
    private string name;
    private string age;
    private string sex;
    public static void main(string[] args) {
        builderexample be = builderexample.builder().name("zhangsan").age("16").sex("male").build();
        
        system.out.println(builderexample.builder().name("zhangsan").age("16").sex("male"));
    }
}

优雅的Java工具库Lombok

@log

@log注解为类添加一个日志对象log,类型为java.util.logging.logger

这个类有很多变种,详情如下:

@commonslog
private static final org.apache.commons.logging.log log = org.apache.commons.logging.logfactory.getlog(logexample.class);

@flogger
private static final com.google.common.flogger.fluentlogger log = com.google.common.flogger.fluentlogger.forenclosingclass();

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

@cleanup注解

@cleanup注解用于关闭资源,调用资源的close()方法

public class cleanupexample {
    
    @sneakythrows({filenotfoundexception.class, exception.class})
    public static void main(string[] args) {
        file file = new file("c:/users/wang2/desktop/11.jpg");
        @cleanup
        fileinputstream is = new fileinputstream(file);
        @cleanup
        fileoutputstream os = new fileoutputstream(new file("c:/users/wang2/desktop/111.jpg"));
        
        byte[] buffer = new byte[1024];
        int length = 0;
        while((length = is.read(buffer)) != -1){
            os.write(buffer, 0, length);
        }
    }
}

注意:抛出的异常被@sneakythrows捕获了

优雅的Java工具库Lombok

@sneakythrows注解

sneaky的意思是偷偷摸摸地,@sneakythrows注解的作用就是取代try...catch代码块,自动生成相应的try...catch代码块