使用Lombok减少JavaBean的重复代码

简介: 使用Lombok减少JavaBean的重复代码

Lombok 介绍

  • Lombok 旨在通过用一组简单的注释来替代它们来减少代码的重复。
  • 例如,简单地将@Data注释添加到数据类中,如下所示,将在IDE中产生许多新方法:

图片.png

IntelliJ IDEA安装Lombok Plugin

  • 定位到 File > Settings > Plugins
  • 点击 Browse repositories
  • 搜索 Lombok Plugin
  • 点击 Install plugin
  • 重启 IDEA


maven依赖

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
</dependency>


Lombok注释

@Getter和@Setter

  • @getter@setter注释分别为字段生成gettersetter
  • 生成的getter正确地遵循boolean 属性的约定,从而产生一个isfoo getter方法名,而不是任何布尔字段foogetfoo
  • 应该注意的是,如果注释字段所属的类包含与要生成的gettersetter同名的方法,则无论参数或返回类型如何,都不会生成相应的方法。
  • @getter@setter注释都采用一个可选的参数来指定生成方法的访问级别。使用这种方法可以克服这些缺点。
  • Lombok annotated code:(使用Lombok 注解的代码)
@Getter @Setter 
private boolean employed = true;
@Setter(AccessLevel.PROTECTED) 
private String name;
  • Equivalent Java source code:(编译后的代码)
private boolean employed = true;
private String name;
public boolean isEmployed() {
return employed;
}
public void setEmployed(final boolean employed) {
this.employed = employed;
}
protected void setName(final String name) {
this.name = name;
}


@NonNull

  • @NONULL注释用于表示对相应成员进行空检查的必要性。当放置在Lombok正在为其生成setter方法的字段时,将生成一个空检查,
  • 如果提供空值,将产生一个nullpointerException
  • 此外,如果Lombok正在为所属类生成构造函数,则该字段将被添加到签名构造函数中。
  • 这个注释反映了IntelliJ IDEAfindbug中的@NONULL@NONULL注解。Lombok对于主题上的这些变体是不可知的。如果Lombok遇到任何注释名称@notnull@non-null的成员,它将受到gener的尊重。
  • Lombok annotated code from the class Family:
@Getter @Setter @NonNull
private List<Person> members;
  • Equivalent Java source code:
@NonNull
private List<Person> members;
public Family(@NonNull final List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
}
@NonNull
public List<Person> getMembers() {
    return members;
}
public void setMembers(@NonNull final List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
}


@ToString

  1. 此注释生成tostring方法的实现。默认情况下,任何非静态字段都将包含在方法的名称-值对中。
  2. 如果需要,可以通过将注释参数包含字段名设置为false来抑制输出中的属性名称。
  3. 可以通过在排除参数中包括它们的字段名,从生成的方法的输出中排除特定字段。
  4. Of参数只能用于列出输出中所需的字段。
  5. 还可以通过将回调超级参数设置为true来包含超类tostring方法的输出。


  • Lombok annotated code:
@ToString(callSuper=true,exclude="someExcludedField")
public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
}


  • Equivalent Java source code:
public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
    @java.lang.Override
    public java.lang.String toString() {
        return "Foo(super=" + super.toString() +
            ", someBoolean=" + someBoolean +
            ", someStringField=" + someStringField + ")";
    }
}


@EqualsAndHashCode

  1. 这个类级注释将生成equals hashcode方法,因为这两个方法本质上是由hashcode契约连接在一起的。
  2. 默认情况下,类中任何非静态或瞬态的字段都将会生成这两种方法。
  3. @tostring一样,提供排除参数是为了防止生成的逻辑中包含字段。只考虑这些字段。
  4. 也像@tostring一样,这个注释有一个回调父级参数。
  5. 在考虑当前类中的字段之前,将它设置为true将等于通过调用超类中的等于来验证相等。
  6. 对于hashcode方法,它将导致将父类的哈希代码的结果合并到计算器中。

 

  • Lombok annotated code:
@EqualsAndHashCode(callSuper=true,exclude={"address","city","state","zip"})
public class Person extends SentientBeing {
    enum Gender { Male, Female }
    @NonNull private String name;
    @NonNull private Gender gender;
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
}


  • Equivalent Java source code:
public class Person extends SentientBeing {
    enum Gender {
        /*public static final*/ Male /* = new Gender() */,
        /*public static final*/ Female /* = new Gender() */;
    }
    @NonNull
    private String name;
    @NonNull
    private Gender gender;
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
    @java.lang.Override
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        if (!super.equals(o)) return false;
        final Person other = (Person)o;
        if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
        if (this.gender == null ? other.gender != null : !this.gender.equals(other.gender)) return false;
        if (this.ssn == null ? other.ssn != null : !this.ssn.equals(other.ssn)) return false;
        return true;
    }
    @java.lang.Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + super.hashCode();
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.gender == null ? 0 : this.gender.hashCode());
        result = result * PRIME + (this.ssn == null ? 0 : this.ssn.hashCode());
        return result;
    }
}


@Data

  • @ToString, @EqualsAndHashCode, 所有属性的@Getter, 所有non-final属性的@Setter@RequiredArgsConstructor的组合,通常情况下,我们使用这个注解就足够了。
  • 虽然@Data非常有用,但它不提供与其他Lombok注释相同的控制粒度。
  • 为了覆盖默认的方法生成行为,请使用其他Lombok注释之一注释该类,字段或方法,并指定必要的参数值以实现所需的效果。
  • @Data确实提供了可用于生成静态工厂方法的单个参数选项。
  • staticConstructor参数的值设置为 所需的方法名称将导致Lombok将生成的构造函数设置为私有的,并公开给定名称的静态工厂方法。
  • Lombok annotated code:
@Data(staticConstructor="of")
public class Company {
    private final Person founder;
    private String name;
    private List<Person> employees;
}


  • Equivalent Java source code:
public class Company {
    private final Person founder;
    private String name;
    private List<Person> employees;
    private Company(final Person founder) {
        this.founder = founder;
    }
    public static Company of(final Person founder) {
        return new Company(founder);
    }
    public Person getFounder() {
        return founder;
    }
    public String getName() {
        return name;
    }
    public void setName(final String name) {
        this.name = name;
    }
    public List<Person> getEmployees() {
        return employees;
    }
    public void setEmployees(final List<Person> employees) {
        this.employees = employees;
    }
    @java.lang.Override
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        final Company other = (Company)o;
        if (this.founder == null ? other.founder != null : !this.founder.equals(other.founder)) return false;
        if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
        if (this.employees == null ? other.employees != null : !this.employees.equals(other.employees)) return false;
        return true;
    }
    @java.lang.Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + (this.founder == null ? 0 : this.founder.hashCode());
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.employees == null ? 0 : this.employees.hashCode());
        return result;
    }
    @java.lang.Override
    public java.lang.String toString() {
        return "Company(founder=" + founder + ", name=" + name + ", employees=" + employees + ")";
    }
}


@Cleanup

使用该注解能够自动释放io资源
  • @Cleanup注释可以用来保证分配的资源被释放。
  •  
  • 当一个局部变量被@Cleanup注释,任何后续代码都被包装在一个 try/finally块中,以保证在当前作用域的末尾调用清理方法。
  • 默认情况下,@Cleanup 假定清理方法被命名为“close”,就像输入和输出流一样。
  • 但是,@Cleanup注释的value参数,可以用来提供不同的方法名称。只有不带参数的清理方法才能用于此批注。
  •  
  • 使用@Cleanup注释时还需要注意一点。
  • 如果清理方法抛出异常,它将抢占抛出方法体内的任何异常。
  • 这可能导致问题的实际原因被掩埋,因此在选择使用Project Lombok的资源管理时应该考虑这个问题。
  • 此外,随着Java 7中的自动化资源管理技术的发展,这种特殊的注释可能会相对短暂。

 

  • Lombok annotated code:

 

  • Equivalent Java source code:
public void testCleanUp() {
    try {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            baos.write(new byte[]{'Y', 'e', 's'});
            System.out.println(baos.toString());
        } finally {
            baos.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}


@Synchronized

  • 在方法上使用synchronized关键字可能导致不幸的结果,任何从事多线程软件工作的开发人员都可以证明这一点。在实例方法的情况下,同步关键字将锁定当前对象(This),或者锁定静态方法的类对象。
  • 这意味着开发人员控制之外的代码有可能锁定同一个对象,从而导致死锁。
  • 通常情况下,最好是显式地锁定一个单独的对象,该对象仅用于该目的,而不以允许非请求锁定的方式暴露。ProjectLombok为此提供了@Synchronous注释。
  • @synchronized注释实例方法将提示Lombok生成一个名为$lock的私有锁定字段,该方法将在执行之前锁定该字段。
  • 类似地,用同样的方式注释静态方法将生成一个名为$lock的私有静态对象,以便静态方法以相同的方式使用。可以通过向@synchronized注释的value参数提供字段名来指定不同的锁定对象。
  • 当提供字段名时,开发人员必须将属性定义为Lombok不会生成它。

 

  • Lombok annotated code:
private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");
@Synchronized
public String synchronizedFormat(Date date) {
    return format.format(date);
}

 

  • Equivalent Java source code:
private final java.lang.Object $lock = new java.lang.Object[0];
private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");
public String synchronizedFormat(Date date) {
    synchronized ($lock) {
        return format.format(date);
    }
}


@SneakyThrows

  • @SneakyThrows可能是Lombok项目批注中最受批评者,因为它是对检查异常的直接攻击。
  • 关于检查异常的使用方面存在很多分歧,有大量开发人员认为他们是一个失败的实验。
  • 这些开发者会喜欢@SneakyThrows。在选中/未选中的异常栏的另一边的那些开发人员很可能会将其视为隐藏潜在问题。
  • IllegalAccessException如果IllegalAccessException或者某个父类未在throws子句中列出,则 投掷通常会生成“未处理的异常”错误:

图片.png

 

  • 注释时@SneakyThrows,错误消失。

 

图片.png

  • 默认情况下,@SneakyThrows将允许在没有在throws子句中声明的情况下引发任何检查的异常。
  • 通过为注释Class<? extends Throwable>的value参数提供一个可抛类(())数组,可以将其限制为一组特定的异常 

 

 

  • Lombok annotated code:
@SneakyThrows
public void testSneakyThrows() {
    throw new IllegalAccessException();
}
  • Equivalent Java source code:
public void testSneakyThrows() {
    try {
        throw new IllegalAccessException();
    } catch (java.lang.Throwable $ex) {
        throw lombok.Lombok.sneakyThrow($ex);
    }
}


局限性

  • 一个重要的问题是无法检测父类的构造函数。这意味着,如果父类没有默认构造函数,那么任何子类都不能使用@Data注释,
  • 而不显式地编写构造函数来使用可用的父类构造函数。
  • 无法支持多种参数构造器的重载

 

参考来源:http://jnb.ociweb.com/jnb/jnbJan2010.html

参考来源: http://blog.csdn.net/v2sking/article/details/73431364#t7



目录
相关文章
|
7天前
|
SQL Java 数据库连接
如何在 Java 代码中使用 JSqlParser 解析复杂的 SQL 语句?
大家好,我是 V 哥。JSqlParser 是一个用于解析 SQL 语句的 Java 库,可将 SQL 解析为 Java 对象树,支持多种 SQL 类型(如 `SELECT`、`INSERT` 等)。它适用于 SQL 分析、修改、生成和验证等场景。通过 Maven 或 Gradle 安装后,可以方便地在 Java 代码中使用。
99 11
|
11天前
|
JSON Java 数据挖掘
利用 Java 代码获取淘宝关键字 API 接口
在数字化商业时代,精准把握市场动态与消费者需求是企业成功的关键。淘宝作为中国最大的电商平台之一,其海量数据中蕴含丰富的商业洞察。本文介绍如何通过Java代码高效、合规地获取淘宝关键字API接口数据,帮助商家优化产品布局、制定营销策略。主要内容包括: 1. **淘宝关键字API的价值**:洞察用户需求、优化产品标题与详情、制定营销策略。 2. **获取API接口的步骤**:注册账号、申请权限、搭建Java开发环境、编写调用代码、解析响应数据。 3. **注意事项**:遵守法律法规与平台规则,处理API调用限制。 通过这些步骤,商家可以在激烈的市场竞争中脱颖而出。
|
28天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
55 3
|
2月前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
64 24
|
1月前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
67 2
|
1月前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
90 5
|
1月前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
72 5
|
2月前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
1月前
|
安全 Java API
Java中的Lambda表达式:简化代码的现代魔法
在Java 8的发布中,Lambda表达式的引入无疑是一场编程范式的革命。它不仅让代码变得更加简洁,还使得函数式编程在Java中成为可能。本文将深入探讨Lambda表达式如何改变我们编写和维护Java代码的方式,以及它是如何提升我们编码效率的。
|
2月前
|
Java
Java将OffsetDateTime格式化为 yyyy-MM-dd HH:mm:ss 如何写代码?
Java将OffsetDateTime格式化为 yyyy-MM-dd HH:mm:ss 如何写代码?
56 0