java创建一个不可变对象

在回答我最近的文章中AutoValue:生成的不可变的值类 , 布兰登认为,这可能是有趣的,看看如何AutoValue比较项目Lombok和Immutables和凯文借调这一点。 我同意这是一个好主意,但是我首先将这篇文章发布为Immutables的简要概述,因为我已经为Lombok和AutoValue提供了类似的帖子。

可从Maven中央存储库中获得Immutables 2.2.5 , 其许可页面指出“ Imputables工具箱和所有必需的依赖项均在Apache软件许可2.0版中涵盖。” 开始吧! 页面指​​出“运行Immutables注释处理器需要Java 7或更高版本。”

像AutoValue这样的不可变对象使用编译时注释来生成定义不可变对象的类的源代码。 因为它们都使用这种方法,所以都只引入了编译时依赖性,并且在应用程序的运行时类路径上不需要它们各自的JAR。 换句话说,不可变的JAR必须位于编译器( javac )的类路径上,而不是位于Java启动器( java )的类路径上。

下一个代码清单( Person.java )中显示了“模板” Person类的代码清单。 它看起来与我在AutoValue演示中使用的Person.java非常相似。

人.java

package dustin.examples.immutables;import org.immutables.value.Value;/*** Represents an individual as part of demonstration of* the Immutables project (http://immutables.github.io/).*/
@Value.Immutable  // concrete extension will be generated by Immutables
abstract class Person
{/*** Provide Person's last name.** @return Last name of person.*/abstract String lastName();/*** Provide Person's first name.** @return First name of person.*/abstract String firstName();/*** Provide Person's birth year.** @return Person's birth year.*/abstract long birthYear();
}

我在AutoValue帖子中列出的“ template”类和“ template”类的唯一区别是包的名称,正在演示哪个产品的Javadoc注释以及(最重要的是)导入并应用于类。 在AutoValue示例中有一个特定的“ create”方法不在Immutables示例中,但这只是因为我没有演示AutoValue生成器的使用,这将使“ create”方法变得不必要。

当我在类路径上适当地指定使用Immutables并使用javac编译上述源代码时,将调用注释处理器并生成以下Java源代码:

ImmutablePerson.java

package dustin.examples.immutables;import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.annotation.Generated;/*** Immutable implementation of {@link Person}.* <p>* Use the builder to create immutable instances:* {@code ImmutablePerson.builder()}.*/
@SuppressWarnings("all")
@Generated({"Immutables.generator", "Person"})
final class ImmutablePerson extends Person {private final String lastName;private final String firstName;private final long birthYear;private ImmutablePerson(String lastName, String firstName, long birthYear) {this.lastName = lastName;this.firstName = firstName;this.birthYear = birthYear;}/*** @return The value of the {@code lastName} attribute*/@OverrideString lastName() {return lastName;}/*** @return The value of the {@code firstName} attribute*/@OverrideString firstName() {return firstName;}/*** @return The value of the {@code birthYear} attribute*/@Overridelong birthYear() {return birthYear;}/*** Copy the current immutable object by setting a value for the {@link Person#lastName() lastName} attribute.* An equals check used to prevent copying of the same value by returning {@code this}.* @param lastName A new value for lastName* @return A modified copy of the {@code this} object*/public final ImmutablePerson withLastName(String lastName) {if (this.lastName.equals(lastName)) return this;String newValue = Objects.requireNonNull(lastName, "lastName");return new ImmutablePerson(newValue, this.firstName, this.birthYear);}/*** Copy the current immutable object by setting a value for the {@link Person#firstName() firstName} attribute.* An equals check used to prevent copying of the same value by returning {@code this}.* @param firstName A new value for firstName* @return A modified copy of the {@code this} object*/public final ImmutablePerson withFirstName(String firstName) {if (this.firstName.equals(firstName)) return this;String newValue = Objects.requireNonNull(firstName, "firstName");return new ImmutablePerson(this.lastName, newValue, this.birthYear);}/*** Copy the current immutable object by setting a value for the {@link Person#birthYear() birthYear} attribute.* A value equality check is used to prevent copying of the same value by returning {@code this}.* @param birthYear A new value for birthYear* @return A modified copy of the {@code this} object*/public final ImmutablePerson withBirthYear(long birthYear) {if (this.birthYear == birthYear) return this;return new ImmutablePerson(this.lastName, this.firstName, birthYear);}/*** This instance is equal to all instances of {@code ImmutablePerson} that have equal attribute values.* @return {@code true} if {@code this} is equal to {@code another} instance*/@Overridepublic boolean equals(Object another) {if (this == another) return true;return another instanceof ImmutablePerson&& equalTo((ImmutablePerson) another);}private boolean equalTo(ImmutablePerson another) {return lastName.equals(another.lastName)&& firstName.equals(another.firstName)&& birthYear == another.birthYear;}/*** Computes a hash code from attributes: {@code lastName}, {@code firstName}, {@code birthYear}.* @return hashCode value*/@Overridepublic int hashCode() {int h = 31;h = h * 17 + lastName.hashCode();h = h * 17 + firstName.hashCode();h = h * 17 + Long.hashCode(birthYear);return h;}/*** Prints the immutable value {@code Person} with attribute values.* @return A string representation of the value*/@Overridepublic String toString() {return "Person{"+ "lastName=" + lastName+ ", firstName=" + firstName+ ", birthYear=" + birthYear+ "}";}/*** Creates an immutable copy of a {@link Person} value.* Uses accessors to get values to initialize the new immutable instance.* If an instance is already immutable, it is returned as is.* @param instance The instance to copy* @return A copied immutable Person instance*/public static ImmutablePerson copyOf(Person instance) {if (instance instanceof ImmutablePerson) {return (ImmutablePerson) instance;}return ImmutablePerson.builder().from(instance).build();}/*** Creates a builder for {@link ImmutablePerson ImmutablePerson}.* @return A new ImmutablePerson builder*/public static ImmutablePerson.Builder builder() {return new ImmutablePerson.Builder();}/*** Builds instances of type {@link ImmutablePerson ImmutablePerson}.* Initialize attributes and then invoke the {@link #build()} method to create an* immutable instance.* <p><em>{@code Builder} is not thread-safe and generally should not be stored in a field or collection,* but instead used immediately to create instances.</em>*/static final class Builder {private static final long INIT_BIT_LAST_NAME = 0x1L;private static final long INIT_BIT_FIRST_NAME = 0x2L;private static final long INIT_BIT_BIRTH_YEAR = 0x4L;private long initBits = 0x7L;private String lastName;private String firstName;private long birthYear;private Builder() {}/*** Fill a builder with attribute values from the provided {@code Person} instance.* Regular attribute values will be replaced with those from the given instance.* Absent optional values will not replace present values.* @param instance The instance from which to copy values* @return {@code this} builder for use in a chained invocation*/public final Builder from(Person instance) {Objects.requireNonNull(instance, "instance");lastName(instance.lastName());firstName(instance.firstName());birthYear(instance.birthYear());return this;}/*** Initializes the value for the {@link Person#lastName() lastName} attribute.* @param lastName The value for lastName * @return {@code this} builder for use in a chained invocation*/public final Builder lastName(String lastName) {this.lastName = Objects.requireNonNull(lastName, "lastName");initBits &= ~INIT_BIT_LAST_NAME;return this;}/*** Initializes the value for the {@link Person#firstName() firstName} attribute.* @param firstName The value for firstName * @return {@code this} builder for use in a chained invocation*/public final Builder firstName(String firstName) {this.firstName = Objects.requireNonNull(firstName, "firstName");initBits &= ~INIT_BIT_FIRST_NAME;return this;}/*** Initializes the value for the {@link Person#birthYear() birthYear} attribute.* @param birthYear The value for birthYear * @return {@code this} builder for use in a chained invocation*/public final Builder birthYear(long birthYear) {this.birthYear = birthYear;initBits &= ~INIT_BIT_BIRTH_YEAR;return this;}/*** Builds a new {@link ImmutablePerson ImmutablePerson}.* @return An immutable instance of Person* @throws java.lang.IllegalStateException if any required attributes are missing*/public ImmutablePerson build() {if (initBits != 0) {throw new IllegalStateException(formatRequiredAttributesMessage());}return new ImmutablePerson(lastName, firstName, birthYear);}private String formatRequiredAttributesMessage() {List<String> attributes = new ArrayList<String>();if ((initBits & INIT_BIT_LAST_NAME) != 0) attributes.add("lastName");if ((initBits & INIT_BIT_FIRST_NAME) != 0) attributes.add("firstName");if ((initBits & INIT_BIT_BIRTH_YEAR) != 0) attributes.add("birthYear");return "Cannot build Person, some of required attributes are not set " + attributes;}}
}

通过检查生成的代码,可以得出一些结论(您会发现它们与我之前的文章中为AutoValue列出的观察结果非常相似):

  • 生成的类扩展了(实现继承)手写的抽象类,从而允许使用代码使用手写类的API,而不必知道正在使用生成的类。
  • 即使没有在源类中直接定义任何字段,也将生成字段; 不可变对象根据提供的abstract访问器方法解释字段。
  • 生成的类不为字段提供“设置” / mutator方法(get / accessor方法)。 这并不奇怪,因为值对象的关键概念是它们是不可变的,甚至这个项目的名称( Immutables )也暗示了这一特征。 请注意, Immutables确实为具有@ Value.Modifiable批注的可修改对象提供了一些功能。
  • 考虑到每个字段的类型,将自动为每个字段适当地生成equals(Object) , hashCode()和toString()的实现。
  • 在源类和方法上的Javadoc注释不会在生成的扩展类上重现。 相反,在生成的类的方法上提供了更简单(更通用)的Javadoc注释,在构建器类的方法上提供了更重要(但仍是通用的)的Javadoc注释。

正如我关于AutoValue所述,使用诸如Immutables生成之类的方法的主要优点之一是,开发人员可以专注于特定类应支持的更简单的高级概念,并且代码生成可以确保较低级别的细节。一致且正确地实施。 但是,使用这种方法时要记住一些事情。

  • 当开发人员受过足够的训练以检查和维护抽象的“源” Java类而不是生成的类时, 不可变对象最有帮助。

    • 下次注释处理再次生成该类时,对生成类的更改将被覆盖,否则必须停止该类的生成,以免发生这种情况。
  • 您需要设置build / IDE,以便将生成的类视为“源代码”,以便抽象类可以编译,并且对生成的类的任何依赖项也可以编译。
  • 如果要使不可变性与可变字段一起使用,则必须格外小心(通常选择使用不可变项或值对象通常是这种情况)。

结论

我的结论几乎与我在AutoValue上发表的文章一样。 Immutables允许开发人员编写更简洁的代码,重点放在高级细节上,并将繁琐的底层(通常容易出错)细节的实现委派给Immutables,以自动生成代码。 这类似于IDE的源代码生成可以执行的操作,但是Immutables相对于IDE方法的优势是Immutables可以在每次编译代码时重新生成源代码,从而使生成的代码保持最新。 Immutables的这一优势也是Java自定义注释处理功能强大的一个很好的例子。

翻译自: https://www.javacodegeeks.com/2016/06/creating-value-objects-immutables.html

java创建一个不可变对象

java创建一个不可变对象_使用不可变对象创建值对象相关推荐

  1. 在mysql中创建表的命令行_如何在命令行创建一个MySQL数据库

    展开全部 第一步:安装MySQL客户端 当然你得确保MySQL客户端已经安装完毕.如果没有的话,可以按62616964757a686964616fe59b9ee7ad9431333339653663照 ...

  2. 利用多态特性,编程创建一个手机类Phones,定义打电话方法call()。创建两个子类:苹果手机类IPhone和安卓手机类APhone,并在各自类中重写方法call(),编写程序入口main()方法

    利用多态特性,编程创建一个手机类Phones,定义打电话方法call().创建两个子类:苹果手机类IPhone和安卓手机类APhone,并在各自类中重写方法call(),编写程序入口main()方法, ...

  3. python使用np.logspace函数在对数刻度上创建一个对数等距数组实战:在对数刻度上创建一个数组(指定数值个数以及是否包含末尾界值)、使用不同的基数(底数)在对数刻度上构建等距数组、可视化

    python使用np.logspace函数在对数刻度上创建一个对数等距数组实战:在对数刻度上创建一个数组(指定数值个数以及是否包含末尾界值).使用不同的基数(底数)在对数刻度上构建等距数组.可视化 目 ...

  4. Java 定义一个抽象类—水果,其中包括getWeight()方法,创建若干水果对象存放在一个水果类型的数组中,输出数组中所有水果的类型、重量。

    Java 定义一个抽象类-水果 其中包括getWeight()方法,编写程序分别创建苹果.桃子.橘子3个类,创建若干水果对象存放在一个水果类型的数组中,输出数组中所有水果的类型.重量. 抽象类Frui ...

  5. mysql 中修改对象_在MySQL中,创建一个数据库后,还可以对象其进行修改,不过这里的修改是指可以修改被创建数据库的相关参数,也可以修改数据库名。...

    [多选题]注射时,在(  )情况下,采用较高的注射速率. [单选题]通常,所设置的模具温度是指和制品接触的模腔内表面在(   ). [单选题]反映某一事件发生强度的指标应选用 [判断题]当试样制备之后 ...

  6. java制作一个简单的画板_【Java】Thymeleaf一个简单示例

    Thymeleaf简单介绍 Thymeleaf是用来开发Web和独立环境项目的服务器端的Java模版引擎 Spring官方支持的服务的渲染模板中,并不包含jsp.而是Thymeleaf和Freemar ...

  7. java做一个客房管理系统定制_管理皮孩子很难?来,教你一个java设计简单的学生管理系统...

    前言: 孩子不听话,那就系统的管理起来,啊哈哈哈哈 学生成绩管理系统 要求: 完善Student类,Student类包含学号.姓名.年级.专业.三门功课的成绩(英语.高数.计算机)的成员变量,完善成绩 ...

  8. 联合查询是要多创建一个实体类么_[译] 如何用 Room 处理一对一,一对多,多对多关系?...

    原文作者:Florina Muntenescu 原文地址: medium.com/androiddeve- 译者:秉心说 译者说:最近在做一款 Rss 阅读器,使用 Room 存储订阅源以及其中的文章 ...

  9. java用for循环查询数据_使用for循环结果创建数据框

    我想创建一个数据框,其中df1值的平均值和df2值的平均值作为新数据框中的列 . 我可以得到要打印的值 for (i in samples) { print(c(with(df1, mean(d18_ ...

最新文章

  1. 啊D扫肉鸡+无远控双开XP3389 termsrvhack.dll_本地测试
  2. Axure之全局变量
  3. 在ASP.NET Core下使用SignalR技术
  4. CentOS8 模块化仓库
  5. 阿群笔记:CentOS7 在线安装 docker 的推荐方法
  6. 教育网系统服务器域名地址,教育网宽带dns服务器IP地址(2021年更新)
  7. 利用Scrapy爬取豆瓣电影
  8. Apache 安装与配置
  9. 【历史上的今天】4 月 3 日:亚马逊卖出第一本书;世界上第一通手机电话;IBM 计算机先驱出生
  10. 【SDOI2015】星际战争(网络流)
  11. 解读Verizon 2018数据泄漏调查报告:窃取身份仍是黑客最有效的攻击手段
  12. 配置Oracle到MySQL透明网关
  13. 哪个软件配音是免费的?分享这几款好用的配音软件
  14. 如何通过安装包安装应用到手机
  15. 《卸甲笔记》-单行函数对比之二
  16. HDU-1814-TwoSAT
  17. 电脑知识:如何将旧电脑文件迁移到新电脑中,包括操作系统
  18. 终于,可以在Excel中直接使用Python!
  19. 为何有人会去搞计算机病毒,为什么会有计算机病毒呢
  20. Inno Setup打包exe

热门文章

  1. 学习手记(2021/3/19~?)
  2. 牛客-小w的魔术扑克【并查集】
  3. P2052-[NOI2011]道路修建【树】
  4. jzoj3463-军训【双重嵌套二分,随机数据水法】
  5. P2055-假期的宿舍【网络流,最大流,最大匹配】
  6. Codeforces Round #684 (Div. 2)
  7. 【数学】礼物(jzoj 2129)
  8. Oracle入门(十四.11)之使用显式游标属性
  9. Java对象引用四个级别(强、软、弱、虚)
  10. Java:关于main方法的10道面试题