jep122
在2019年4月,Java语言架构师Brian Goetz提交了JEP草案,提议向Java添加两个新功能 。 现在,草案全部长大了,我们有两个新的JEP。 JEP 359和JEP360。在本文中,我们将重点介绍JEP 359记录(预览) 。
JEP 359:记录
JEP 359旨在通过引入一种称为records
的新型类型声明来扩展Java。 记录应该为声明“浅层不变数据的透明持有人”的类提供一种新的紧凑语法。 就像enum
,记录是类的一种受限形式。 它声明其表示形式,并提交与该表示形式匹配的API。 记录缺乏类通常享有的自由度-能够将类的API与表示分离。 作为回报,他们获得了很大程度的简洁性。 记录是“状态,整个状态,除了状态之外什么都没有”。
在Brian的建议中,记录具有以下形式:
record Point(int x, int y) { }
它具有名称,状态描述和主体。 大多数标准成员应该以机械方式派生,尤其是构造,解构,平等和展示的表示形式和协议。
此外:
记录像枚举一样都是类。 记录声明可以具有类声明可以进行的大多数操作:可访问性修饰符,Javadoc,注释,实现子句和类型变量(尽管记录本身是隐式最终的。)组件声明可以具有注释和可访问性修饰符(尽管组件本身是隐式的私有和最终的)。 主体可以包含静态字段,静态方法,静态初始化器,构造函数,实例方法,实例初始化器和嵌套类型。 布赖恩·格茨
动机,目标和非目标
因此,正如Brian在原始JEP草案中所写的那样,Java被批评为过于冗长或具有过多的“仪式”,其原因之一就是类不过是“普通数据载体”。 为了正确地编写一个简单的数据载体类,您必须编写许多低值,重复且容易出错的代码,例如constructors
, accessors
, equals()
, hashCode()
, toString()
等。因此,此功能旨在使编写用于对简单数据聚合进行建模的Java代码更易于编写,读取和更正。
但是,他指出,尽管有些人可能将记录主要视为减少样板,但是该功能还有一个语义目标: 将数据建模为data 。
JEP 359明确指出,此功能的目的不是“宣扬样板之战;它只是为了宣告战争”。 特别是,使用JavaBean命名约定来解决可变类的问题并不是目标。”
现在,让我们更详细地查看记录以及它们可以做什么和不能做什么。
限制条件
记录的功能是有限的。 他们不能扩展任何其他类,只能声明与状态描述组件相对应的私有final字段以外的实例字段。 这意味着只有状态描述才能定义表示。
记录不能是抽象的,它们是隐式最终的。 同样,这是为了确保记录的API仅由其状态描述定义,并且以后不能由另一个类或记录进行增强。
记录的组成部分是隐式最终的,它遵循应用于数据聚合的默认不变策略。
除了上述限制外,记录的行为类似于普通类,因为它们可以是顶级或嵌套的,通用的,可以实现接口并可以使用new关键字实例化。 记录的主体可以声明静态方法,静态字段,静态初始化器,构造函数,实例方法,实例初始化器和嵌套类型。 记录及其组成部分可以在状态描述中进行注释。 嵌套记录是隐式静态的,这是一种避免立即封闭实例的措施,该实例会以静默方式将状态添加到记录中。
语法
JEP 359提供了以下记录语法实例:
RecordDeclaration:
{ClassModifier} record TypeIdentifier [TypeParameters]
(RecordComponents) [SuperInterfaces] [RecordBody]
RecordComponents:
{RecordComponent {, RecordComponent}}
RecordComponent:
{Annotation} UnannType Identifier
RecordBody:
{ {RecordBodyDeclaration} }
RecordBodyDeclaration:
ClassBodyDeclaration
RecordConstructorDeclaration
RecordConstructorDeclaration:
{Annotation} {ConstructorModifier} [TypeParameters] SimpleTypeName
[Throws] ConstructorBody
明确声明记录的成员
如果开发人员愿意,则可以显式声明从状态描述自动派生的所有成员。 Goetz警告,但是,不小心这样做会破坏记录的语义不变性。
还请参见:
反射API
JEP进一步指出,它将在java.lang.Class中添加以下公共方法:
-
RecordComponent[]
getRecordComponents()
-
boolean isRecord()
方法getRecordComponents()
返回一个java.lang.reflect.RecordComponent对象的数组,其中java.lang.reflect.RecordComponent是一个新类。 数组的元素对应于记录的组件。 可以从数组的RecordComponent中提取更多信息,包括名称,类型,泛型类型,注释及其访问方法。
如果将给定的类声明为记录,则isRecord()
方法将返回true。
备择方案
JEP 359指出,记录可以看作是元组的名义形式,但它们通常会导致劣等的汇总。 Java原理的一个重要方面是名称很重要,类和成员具有有意义的名称,而元组及其组件可以具有无关紧要的字符串名称,这是不希望的。
类还通过其构造函数支持状态验证,而元组则不支持。 而且类可以具有与其状态相关的行为,而元组作为原始数据无法提供。
依存关系
正如本文开头所提到的,JEP 359和JEP 360在一起是因为它们都来自同一JEP草案。 这样,由于记录可以与密封类型并存以形成称为代数数据类型的事实,因此JEP 360被列为依赖项。
有关更多信息,请全面了解JEP 359 。
jep122