Professional Documents
Culture Documents
A First Look at Records in Java 14 - DZone
A First Look at Records in Java 14 - DZone
A First Look at Records in Java 14 - DZone
Culture and Data Software Design and Coding Testing, Deployment, and
Partner Resources
https://dzone.com/articles/a-first-look-at-records-in-java-14 1/12
19/1/23, 10:08 A First Look at Records in Java 14 - DZone
Culture and Data Software Design and Coding Testing, Deployment, and
https://dzone.com/articles/a-first-look-at-records-in-java-14 2/12
19/1/23, 10:08 A First Look at Records in Java 14 - DZone
REFCARDS (/REFCARDZ)
/ A First Look at Records in Java 14
TREND REPORTS (/users/login.html)
DZone (https://dzone.com) / (/)Coding (https://dzone.com/coding) / Java (https://dzone.com/java)
(/TRENDREPORTS)
EVENTS (/WEBINARS) (/search)
Culture and Data Software Design and Coding Testing, Deployment, and
A good way to think of how records are implemented in the language is to remember
enums. An enum is also a class that has special semantics with a nicer syntax. Since both
are still classes, many of the features available in classes are preserved, so there is a
balance between simplicity and flexibility in their design.
Records are a preview language feature, which means that, although it is fully
implemented, it is not yet standardized in the JDK and can only be used by activating a
flag. Preview language features can be updated or even removed in future versions.
Similar to switch expressions, it may become final and permanent in a future version.
A Record Example
Here’s an example of how a basic record looks like:
https://dzone.com/articles/a-first-look-at-records-in-java-14 4/12
19/1/23, 10:08
p A First Look at Records in Java 14 - DZone
Java
1 package examples;
2
3 record Person (String firstName, String lastName) {}
We have a Person record defined in a package with two components: firstName and
lastName , and an empty body.
Shell
1 > javac --enable-preview --release 14 Person.java
2 Note: Person.java uses preview language features.
3 Note: Recompile with -Xlint:preview for details.
Plain Text
1 Classfile examples/Person.class
2 Last modified Dec 22, 2019; size 1273 bytes
3 SHA-256 checksum 6f1b325121ca32a0b6127180eff29dcac4834f9c138c9613c526a4202fef972f
4 Compiled from "Person.java"
5 final class examples.Person extends java.lang.Record
6 minor version: 65535
7 major version: 58
8 flags: (0x0030) ACC_FINAL, ACC_SUPER
9 this_class: #8 // examples/Person
10 super_class: #2 // java/lang/Record
11 interfaces: 0, fields: 2, methods: 6, attributes: 4
12 Constant pool:
13 #1 = Methodref #2.#3 // java/lang/Record."":()V
14 #2 = Class #4 // java/lang/Record
15 #3 = NameAndType #5:#6 // "":()V
16 #4 = Utf8 java/lang/Record
17 #5 = Utf8
18 #6 = Utf8 ()V
https://dzone.com/articles/a-first-look-at-records-in-java-14 5/12
19/1/23, 10:08 A First Look at Records in Java 14 - DZone
18 #6 Utf8 ()V
19 #7 = Fieldref #8.#9 // examples/Person.firstName:Ljava/lang/String;
20 #8 = Class #10 // examples/Person
21 #9 = NameAndType #11:#12 // firstName:Ljava/lang/String;
22 #10 = Utf8 examples/Person
23 #11 = Utf8 firstName
24 #12 = Utf8 Ljava/lang/String;
25 #13 = Fieldref #8.#14 // examples/Person.lastName:Ljava/lang/String;
26 #14 = NameAndType #15:#12 // lastName:Ljava/lang/String;
27 #15 = Utf8 lastName
28 #16 = Fieldref #8.#9 // examples/Person.firstName:Ljava/lang/String;
29 #17 = Fieldref #8.#14 // examples/Person.lastName:Ljava/lang/String;
30 #18 = InvokeDynamic #0:#19 // #0:toString:
(Lexamples/Person;)Ljava/lang/String;
31 #19 = NameAndType #20:#21 // toString:(Lexamples/Person;)Ljava/lang/String;
32 #20 = Utf8 toString
33 #21 = Utf8 (Lexamples/Person;)Ljava/lang/String;
34 #22 = InvokeDynamic #0:#23 // #0:hashCode:(Lexamples/Person;)I
35 #23 = NameAndType #24:#25 // hashCode:(Lexamples/Person;)I
36 #24 = Utf8 hashCode
37 #25 = Utf8 (Lexamples/Person;)I
38 #26 = InvokeDynamic #0:#27 // #0:equals:(Lexamples/Person;Ljava/lang/Object;)Z
39 #27 = NameAndType #28:#29 // equals:(Lexamples/Person;Ljava/lang/Object;)Z
40 #28 = Utf8 equals
41 #29 = Utf8 (Lexamples/Person;Ljava/lang/Object;)Z
42 #30 = Utf8 (Ljava/lang/String;Ljava/lang/String;)V
43 #31 = Utf8 Code
44 #32 = Utf8 LineNumberTable
45 #33 = Utf8 MethodParameters
46 #34 = Utf8 ()Ljava/lang/String;
47 #35 = Utf8 ()I
48 #36 = Utf8 (Ljava/lang/Object;)Z
49 #37 = Utf8 SourceFile
50 #38 = Utf8 Person.java
51 #39 = Utf8 Record
52 #40 = Utf8 BootstrapMethods
53 #41 = MethodHandle 6:#42 // REF_invokeStatic
java/lang/runtime/ObjectMethods.bootstrap:
(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Lj
ava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
54 #42 = Methodref #43.#44 // java/lang/runtime/ObjectMethods.bootstrap:
(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Lj
ava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
55 #43 = Class #45 // java/lang/runtime/ObjectMethods
56 #44 = NameAndType #46:#47 // bootstrap:
(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Lj
ava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
57 #45 = Utf8 java/lang/runtime/ObjectMethods
58 #46 = Utf8 bootstrap
59 #47 = Utf8
(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Lj
ava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
60 #48 = String #49 // firstName;lastName
https://dzone.com/articles/a-first-look-at-records-in-java-14 6/12
19/1/23, 10:08 A First Look at Records in Java 14 - DZone
60 #48 String #49 // firstName;lastName
61 #49 = Utf8 firstName;lastName
62 #50 = MethodHandle 1:#7 // REF_getField
examples/Person.firstName:Ljava/lang/String;
63 #51 = MethodHandle 1:#13 // REF_getField
examples/Person.lastName:Ljava/lang/String;
64 #52 = Utf8 InnerClasses
65 #53 = Class #54 // java/lang/invoke/MethodHandles$Lookup
66 #54 = Utf8 java/lang/invoke/MethodHandles$Lookup
67 #55 = Class #56 // java/lang/invoke/MethodHandles
68 #56 = Utf8 java/lang/invoke/MethodHandles
69 #57 = Utf8 Lookup
70 {
71 private final java.lang.String firstName;
72 descriptor: Ljava/lang/String;
73 flags: (0x0012) ACC_PRIVATE, ACC_FINAL
74
75 private final java.lang.String lastName;
76 descriptor: Ljava/lang/String;
77 flags: (0x0012) ACC_PRIVATE, ACC_FINAL
78
79 public examples.Person(java.lang.String, java.lang.String);
80 descriptor: (Ljava/lang/String;Ljava/lang/String;)V
81 flags: (0x0001) ACC_PUBLIC
82 Code:
83 stack=2, locals=3, args_size=3
84 0: aload_0
85 1: invokespecial #1 // Method java/lang/Record."":()V
86 4: aload_0
87 5: aload_1
88 6: putfield #7 // Field firstName:Ljava/lang/String;
89 9: aload_0
90 10: aload_2
91 11: putfield #13 // Field lastName:Ljava/lang/String;
92 14: return
93 LineNumberTable:
94 line 3: 0
95 MethodParameters:
96 Name Flags
97 firstName
98 lastName
99
100 public java.lang.String toString();
101 descriptor: ()Ljava/lang/String;
102 flags: (0x0001) ACC_PUBLIC
103 Code:
104 stack=1, locals=1, args_size=1
105 0: aload_0
106 1: invokedynamic #18, 0 // InvokeDynamic #0:toString:
(Lexamples/Person;)Ljava/lang/String;
107 6: areturn
108 LineNumberTable:
109 line 3: 0
https://dzone.com/articles/a-first-look-at-records-in-java-14 7/12
19/1/23, 10:08 A First Look at Records in Java 14 - DZone
0 e 3: 0
110
111 public final int hashCode();
112 descriptor: ()I
113 flags: (0x0011) ACC_PUBLIC, ACC_FINAL
114 Code:
115 stack=1, locals=1, args_size=1
116 0: aload_0
117 1: invokedynamic #22, 0 // InvokeDynamic #0:hashCode:
(Lexamples/Person;)I
118 6: ireturn
119 LineNumberTable:
120 line 3: 0
121
122 public final boolean equals(java.lang.Object);
123 descriptor: (Ljava/lang/Object;)Z
124 flags: (0x0011) ACC_PUBLIC, ACC_FINAL
125 Code:
126 stack=2, locals=2, args_size=2
127 0: aload_0
128 1: aload_1
129 2: invokedynamic #26, 0 // InvokeDynamic #0:equals:
(Lexamples/Person;Ljava/lang/Object;)Z
130 7: ireturn
131 LineNumberTable:
132 line 3: 0
133
134 public java.lang.String firstName();
135 descriptor: ()Ljava/lang/String;
136 flags: (0x0001) ACC_PUBLIC
137 Code:
138 stack=1, locals=1, args_size=1
139 0: aload_0
140 1: getfield #16 // Field firstName:Ljava/lang/String;
141 4: areturn
142 LineNumberTable:
143 line 3: 0
144
145 public java.lang.String lastName();
146 descriptor: ()Ljava/lang/String;
147 flags: (0x0001) ACC_PUBLIC
148 Code:
149 stack=1, locals=1, args_size=1
150 0: aload_0
151 1: getfield #17 // Field lastName:Ljava/lang/String;
152 4: areturn
153 LineNumberTable:
154 line 3: 0
155 }
156 SourceFile: "Person.java"
157 Record:
158 java.lang.String firstName;
159 descriptor: Ljava/lang/String;
https://dzone.com/articles/a-first-look-at-records-in-java-14 8/12
19/1/23, 10:08 A First Look at Records in Java 14 - DZone
5 desc pto : ja a/ a g/St g;
160
161 java.lang.String lastName;
162 descriptor: Ljava/lang/String;
163
164 BootstrapMethods:
165 0: #41 REF_invokeStatic java/lang/runtime/ObjectMethods.bootstrap:
(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Lj
ava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
166 Method arguments:
167 #8 examples/Person
168 #48 firstName;lastName
169 #50 REF_getField examples/Person.firstName:Ljava/lang/String;
170 #51 REF_getField examples/Person.lastName:Ljava/lang/String;
171 InnerClasses:
172 public static final #57= #53 of #55; // Lookup=class
java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
1. The class is marked final , which means we cannot create a subclass of it.
2. The class extends java.lang.Record , which is the base class for all records, much
like java.lang.Enum is the base class for all enums.
3. There are two private final fields named after the two components of the record:
firstName and lastName .
Java
1 record Person (String firstName, String lastName) {
2 static int x;
3 }
We can define static methods and instance methods that can operate on the state of the
object:
Java
1 record Person (String firstName, String lastName) {
2 static int x;
3
4 public static void doX() {
5 x++;
6 }
7
8 public String getFullName() {
9 return firstName + " " + lastName;
10 }
11 }
https://dzone.com/articles/a-first-look-at-records-in-java-14 10/12
19/1/23, 10:08 A First Look at Records in Java 14 - DZone
We can also add constructors, and modify the canonical constructor (the one that takes
the two String parameters). If we want to override the canonical constructor, we can
omit the parameters and the assignments to the fields:
Java
1 record Person (String firstName, String lastName) {
2 public Person {
3 if(firstName == null || lastName == null) {
4 throw new IllegalArgumentException("firstName and lastName must not be null");
5 // We can also omit assigning fields, the compiler will auto-add them
6 }
7 }
8
9 public Person(String fullName) {
10 this(fullName.split(" ")[0], fullName.split(" ")[1]);
11 }
12 }
Conclusion
Records introduce the capability of properly implementing data classes, without the
need to write verbose code. Plain data classes are reduced from several lines of code to a
one-liner. There are other language features in progress that work well with records,
such as pattern matching. For a much deeper dive into records and background
information, see Brian Goetz’s exploratory document on OpenJDK
(https://cr.openjdk.java.net/~briangoetz/amber/datum.html).
Further Reading
Introducing Java Record (https://dzone.com/articles/introducing-java-record)
Published at DZone with permission of Mahmoud Anouti, DZone MVB. See the original article here.
(https://mahmoudanouti wordpress com/2019/12/22/a-first-look-at-records-in-java-14/)
https://dzone.com/articles/a-first-look-at-records-in-java-14 11/12
19/1/23, 10:08 A First Look at Records in Java 14 - DZone
(https://mahmoudanouti.wordpress.com/2019/12/22/a first look at records in java 14/)
Opinions expressed by DZone contributors are their own.
Popular on DZone
Multi-Cloud Database Deep Dive (/articles/multi-cloud-database-deep-dive?
fromrel=true)
https://dzone.com/articles/a-first-look-at-records-in-java-14 12/12