优雅的JAVA工具库LOMBOK

作者: 程序员日常填坑 | 来源:发表于2019-01-02 11:37 被阅读11次

    优雅的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栗子

    如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

    Eclipse安装Lombok支持

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

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

    点击【Install/Update】

    引入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,用于向生成的方法,构造器,参数添加注解

    反编译后结果

    @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,仅包含明确包含的属性

    如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

    @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注解

    如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

    等同于@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"));

        }

    }

    @Log

    如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。 

    @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工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

    @SneakyThrows注解

    如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。 

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

    相关文章

      网友评论

        本文标题:优雅的JAVA工具库LOMBOK

        本文链接:https://www.haomeiwen.com/subject/ofxzlqtx.html