zoukankan      html  css  js  c++  java
  • lombok的介绍、使用、简单分析和插件

    学习下Lombok。

    关于POJO

    Java面向对象编程中的特性中有封闭性和安全性。封闭性即对类中的域变量进行封闭操作,即用private来修饰他们。如此一来,其他类就不能对该变量访问了。这样,我们就将这些变量封闭在了类的内部,提高了数据的安全性。

    当我们想要操作这些域变量的时候,有两种办法。第一种是通过public方式的构造器(或称构造函数),对象一实例化就对该变量赋值。第二种就是通过set和get方法对变量进行赋值和取值。这样就能提高域变量的安全性,同时又保证了域变量的封装型。 

    所以当我们创建POJO类时,都会毫不犹豫的让开发工具对域变量生成set、get方法。虽然不是我们自己手动添加(快捷键或菜单快速生成),但每个类都要做重复的生成操作也是一件很烦人的事。而且当变量名或者是修饰符改变了的话,我们就要删除set、get方法并重新生成,又是一项重复又枯燥的操作。Lombok就是一个为了提高生产效率,让我们免去这些重复操作的神器。

    Lombok的介绍

    Project Lombok makes java a spicier language by adding 'handlers' that know how to build and compile simple, boilerplate-free, not-quite-java code.

    上面这段话是官方的介绍,意思是Lombok通过一些特殊的处理,可以让Java编程变得简洁和快速。

    Lombok的使用

    Lombok能以简单的注解形式来简化Java代码的编写,提高开发人员的开发效率。比如在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。意思就是说,在源码中不需要编写getter和setter方法,但是在编译生成的字节码文件中却会有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。

    使用Lombok需要引用Jar包依赖,而在Maven中添加依赖十分简单。

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.20</version>
        <scope>provided</scope>
    </dependency>

    下面是Lombok提供的一些常用注解的介绍与使用。

    @Data注解

    @Data注解使用在类上,会为类的所有属性自动生成setter/getter、equals、canEqual、hashCode、toString方法。要注意的是,如果是final修饰符修饰的属性,则不会为该属性生成setter方法。

    @Data
    public class DataExample {
        private final String name;
        
        @Setter(AccessLevel.PACKAGE)
        private int age;
        
        private double score;
        
        private String[] tags;
      
        @ToString(includeFieldNames=true)
        @Data(staticConstructor="of")
        public static class Exercise<T> {
            private final String name;
            private final T value;
        }
    }

    在开发中建议尽量少直接使用@Data注解,而是换成@Setter、@Getter、@NoArgsConstructor、@AllArgsConstructor、@ToString。

    @Getter/@Setter注解

    因为@Data集合了@ToString、@EqualsAndHashCode、@Getter/@Setter、@RequiredArgsConstructor的所有特性,很多时候我们可能并不需要那么多的特性,因此Lombok提供了更精细的注解@Getter/@Setter,这个注解使用在属性上会为该属性自动生成getter/setter方法。

    public class GetterSetterExample {
        @Getter
        @Setter
        private int age = 10;
      
        @Setter(AccessLevel.PROTECTED)
        private String name;
        
        @Override
        public String toString() {
            return String.format("%s (age: %d)", name, age);
        }
    }

    @NonNull注解

    @NonNull注解使用在属性或构造器上,Lombok会生成一个非空的声明,可用于校验参数,能帮助避免空指针。

    public class NonNullExample extends Something {
        private String name;
        
        public NonNullExample(@NonNull Person person) {
            super("Hello");
            this.name = person.getName();
        }
    }

    如果不使用@NonNull注解,则要手动对属性/构造器进行非空校验。

    public class NonNullExample extends Something {
        private String name;
      
        public NonNullExample(Person person) {
            super("Hello");
            if (person == null) {
                throw new NullPointerException("person");
            }
            this.name = person.getName();
        }
    }

    @Cleanup注解

    @Cleanup注解能帮助我们自动调用close()方法,很大程度上简化了代码。

    public class CleanupExample {
        public static void main(String[] args) throws IOException {
            @Cleanup
            InputStream in = new FileInputStream(args[0]);
            
            @Cleanup
            OutputStream out = new FileOutputStream(args[1]);
            
            byte[] b = new byte[10000];
            while (true) {
                int r = in.read(b);
                if (r == -1) break;
                out.write(b, 0, r);
            }
        }
    }

    如果不使用@Lombok注解,则需要手动调用colse()关闭输入/输出流。

    public class CleanupExample {
        public static void main(String[] args) throws IOException {
            InputStream in = new FileInputStream(args[0]);
            try {
                OutputStream out = new FileOutputStream(args[1]);
                try {
                    byte[] b = new byte[10000];
                    while (true) {
                        int r = in.read(b);
                        if (r == -1) break;
                            out.write(b, 0, r);
                    }
                } finally {
                    if (out != null) {
                        out.close();
                    }
                }
            } finally {
                if (in != null) {
                    in.close();
                }
            }
        }
    }

    @EqualsAndHashCode注解

    默认情况下,会使用所有非静态(non-static)和非瞬态(non-transient)属性来生成equals和hasCode,也能通过exclude注解来排除一些属性。

    @EqualsAndHashCode(exclude={"id", "shape"})
    public class EqualsAndHashCodeExample {
        private transient int transientVar = 10;
        private String name;
        private double score;
        private Shape shape = new Square(5, 10);
        private String[] tags;
        private int id;
      
        public String getName() {
            return this.name;
        }
      
        @EqualsAndHashCode(callSuper=true)
        public static class Square extends Shape {
            private final int width, height;
            public Square(int width, int height) {
                this.width = width;
                this.height = height;
            }
        }
    }

    @ToString注解

    在类上使用@ToString注解,Lombok会生成一个toString()方法,默认情况下,会输出类名、所有属性(会按照属性定义顺序),用逗号来分割。

    而通过将includeFieldNames参数设为true,就能明确的输出toString()属性。

    @ToString(exclude="id")
    public class ToStringExample {
        private static final int STATIC_VAR = 10;
        private String name;
        private Shape shape = new Square(5, 10);
        private String[] tags;
        private int id;
    
        public String getName() {
            return this.getName();
        }
    
        @ToString(callSuper=true, includeFieldNames=true)
        public static class Square extends Shape {
            private final int width, height;
    
            public Square(int width, int height) {
                this.width = width;
                this.height = height;
            }
        }
    }

    @NoArgsConstructor、@RequiredArgsConstructor和@AllArgsConstructor注解

    三个注解分别对应无参构造器、部分参数构造器和全参构造器。Lombok没法实现多种参数构造器的重载。

    @RequiredArgsConstructor(staticName = "of")
    @AllArgsConstructor(access = AccessLevel.PROTECTED)
    public class ConstructorExample<T> {
        private int x, y;
        
        @NonNull
        private T description;
      
        @NoArgsConstructor
        public static class NoArgsExample {
            @NonNull
            private String field;
        }
    }

    加上staticName参数会生成一个of()的静态方法。

    默认生成的方法事public的,如果想要生成其他方法修饰符修饰的方法,可以设置access参数。

    Lombok简单分析

    Lombok的基本原理是在编译的时候通过解析注解去自动生成相应的代码。JDK5在引入注解的同时,提供了两种解析注解的方式,一种是运行时解析,一种是编译时解析。

    运行时编译

    运行时能够解析的注解,必须是将注解定义中的@Retention注解设置为RUNTIME,这样才可以通过Java的反射机制拿到使用注解的类信息。在java.lang.reflect反射包中提供了一个AnnotatedElement接口,这个接口定义了获取注解信息的几个方法,Class、Constructor、Field、Method和Package等都实现了这个接口。

    编译时解析

    编译时的解析有两种机制:

    1.Annotation Processing Tool(apt)

    apt自JDK5产生,在JDK7已经被标记为过期,不推荐使用,且在JDK8中已经被彻底删除了。自JDK6开始可以使用Pluggable Annotation Processing API来替换它。apt被替换的原因主要有两个,一个是它的api都在com.sun.mirror非标准包下,一个是它没有被集成到javac中,需要额外运行。

    2.Pluggable Annotation Processing API(JSR 269)

    JSR 269自JDK6加入,作为apt的替代方案,它解决了apt的两个问题,javac在执行的时候会调用实现了该API的程序,这样我们可以对编译器做一些增强。

    事实上,Lombok本质上就是一个实现了JSR 269 API的程序。

    Lombok的插件

    Lombok的插件是提供给IDE的,目的是为了方便开发者在编写源码的时候能看到Lombok通过注解自动生成的代码,没有安装插件的情况下也可能会发生编译错误。

    Idea安装Lombok插件

    Idea可以到插件库(Plugins)中搜索Lombok Plugin直接安装,简单又方便。

    Eclipse安装Lombok插件

    Eclipes则需要到官网下载插件到本地,再通过命令行安装插件。

    1.到官网下载Lombok插件:https://projectlombok.org/download.html

    2.命令行切换到Lombok插件的下载目录,运行命令:java -jar lombok.jar。

    3.在弹出的可视化界面中选择Eclipse的安装/解压目录并点击Install/Update即可。

    安装完成之后,Eclipse的安装/解压路径下会多出一个lombok.jar文件,并且其eclipse.ini配置文件也会添加两行Lombok配置的代码:

    -javaagent:lombok.jar
    -Xbootclasspath/a:lombok.jar

    这样,在添加完Lombok提供的注解之后就可以在Outline中查看到Lombok自动生成的代码了。

    总结

    Lombok是个好东西,能有效提高开发效率,使代码变得简洁,维护起来也变得简单了。但是有一个大的缺点就是Lombok不支持多个参数的构造器重载。

    另外要注意的是,手动写的代码会覆盖Lombok自动生成的代码。比如如果在源代码中手写了getter/setter方法的话,会覆盖Lombok生成的getter/setter方法,或者说Lombok在编译的时候就不会去生成已经存在的getter/setter。

    "如果必须完成一件自己不喜欢的事,最好的做法就是尽可能快地将这件事做好,然后无后续地结束。"

  • 相关阅读:
    autocomplete自动完成搜索提示仿google提示效果
    实现子元素相对于父元素左右居中
    javascript 事件知识集锦
    让 IE9 以下的浏览器支持 Media Queries
    「2013124」Cadence ic5141 installation on CentOS 5.5 x86_64 (limited to personal use)
    「2013420」SciPy, Numerical Python, matplotlib, Enthought Canopy Express
    「2013324」ClipSync, Youdao Note, GNote
    「2013124」XDMCP Configuration for Remote Access to Linux Desktop
    「2013115」Pomodoro, Convert Multiple CD ISO to One DVD ISO HowTo.
    「2013123」CentOS 5.5 x86_64 Installation and Configuration (for Univ. Labs)
  • 原文地址:https://www.cnblogs.com/yanggb/p/11187186.html
Copyright © 2011-2022 走看看