A First Look at Records in Java 14 - DZone

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 12

19/1/23, 10:08 A First Look at Records in Java 14 - DZone

(/) REFCARDS (/REFCARDZ) 


TREND REPORTS (/users/login.html)
(/TRENDREPORTS)  (/search)
EVENTS (/WEBINARS)

Culture and Data Software Design and Coding Testing, Deployment, and

Methodologies Engineering Architecture (/software- (/coding) Maintenance (/testing-


(/culture-and- (/data- design-and-architecture) deployment-and-maintenance)
methodologies) engineering)

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

(/) REFCARDS (/REFCARDZ) 


TREND REPORTS (/users/login.html)
(/TRENDREPORTS)  (/search)
EVENTS (/WEBINARS)

Culture and Data Software Design and Coding Testing, Deployment, and

Methodologies Engineering Architecture (/software- (/coding) Maintenance (/testing-


(/culture-and- (/data- design-and-architecture) deployment-and-maintenance)
methodologies) engineering)

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 First Look at Records in Java 14


Methodologies
(/culture-and-
Engineering
(/data-
Architecture (/software-
design-and-architecture)
(/coding) Maintenance (/testing-
deployment-and-maintenance)
Here's a first look engineering)
methodologies) at records in Java 14.

by Mahmoud Anouti (/users/942829/mma113.html)  · Jan. 07, 20 · News

 Like (19)  Comment (0)  Save  Tweet  Share  53.98K Views

Here's a first look at records in Java 14!

The upcoming release of Java will be version 14 scheduled to be in general availability in


March 2020. Similar to the already released versions under the new 6-month release
cycle, JDK 14 (https://openjdk.java.net/projects/jdk/14/) is expected to have several
new features at both the language and JVM levels.
https://dzone.com/articles/a-first-look-at-records-in-java-14 3/12
19/1/23, 10:08 A First Look at Records in Java 14 - DZone

If we look at the feature (/)list, however, (/REFCARDZ)


weTREND
noticeREPORTS
quite a few language features  that are
REFCARDS  (/users/login.html)
(/TRENDREPORTS)
EVENTS (/WEBINARS) (/search)
highly anticipated by developers: records, switch expressions (which exist in JDK 13 but
ABOUT US
Culture and
in preview
About mode), and Data
DZone (/pages/about)
Software Design and
pattern matching. Let’s have a lookCoding Testing, Deployment, and
at records that seems to be an
Methodologies
Send Engineering
feedback (mailto:support@dzone.com) Architecture (/software- (/coding) Maintenance (/testing-
interesting addition to the language.
Careers (https://careers.dzone.com/)
(/culture-and- (/data- design-and-architecture) deployment-and-maintenance)
Sitemap (/sitemap)
methodologies) engineering)
ADVERTISE You may also like: Introducing Java Record
Advertise with DZone (https://advertise.dzone.com)
(https://dzone.com/articles/introducing-java-record)
CONTRIBUTE ON DZONE
Article Submission Guidelines (/articles/dzones-article-submission-guidelines)
Prerequisites
Become a Contributor (/pages/contribute)
Visit the Writers' Zone (/writers-zone)
All that we’re going to need is the JDK 14 Early-Access binary from the OpenJDK website:
https://jdk.java.net/14/ (https://jdk.java.net/14/).
LEGAL
Terms of Service (/pages/tos)
Privacy Policy (/pages/privacy)
What Is a Record?
CONTACT US
A record
600 is basically
Park Offices Drive a “data class,” a special kind of class that is intended to hold pure
Suite 300
data in it. The semantics of
Durham, NC 27709
records already exist in similar constructs in other languages
such as data classes
support@dzone.com in Kotlin. By declaring a type as a record, the developer is clearly
(mailto:support@dzone.com)
+1 (919) 678-0300 (tel:+19196780300)
expressing their intention that the type represents only data. The syntax for declaring a
record is much simpler and concise, compared to using a normal class where you
Let's be friends:    
typically need to implement core Object methods like equals() and hashCode()
(/pages/feeds)
(https://twitter.com/DZoneInc)
(https://www.facebook.com/DZoneInc)
(https://www.linkedin.com/company/dzone/)
(often referred to as “boilerplate” code). Records seem to be an interesting choice when
modeling things like domain model classes (potentially to be persisted via ORM), or data
DZone.com is powered by  (https://devada.com/answerhub/)
transfer objects (DTOs). AnswerHub logo

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.

Let’s try to compile it — notice the --enable-preview option:

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.

How Does it Look Under the Hood?


As mentioned previously, a record is just a class with the purpose of holding and
exposing data. Let’s have a look at the generated bytecode with the javap tool:
Shell
1 >javap -v -p Person.class

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

Interesting… Several things we can notice:

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 .

4. There is a public constructor that is generated for us: public


examples.Person(java.lang.String, java.lang.String) . By looking at its body,
it’s easy to see that it just assigns the two arguments to the two fields. The
constructor is equivalent to:
Java
1 public Person(String firstName, String lastName) {
2    this.firstName = firstName;
3    this.lastName = lastName;
4 }

5. There are two getter methods named firstName() and lastName() .


6. Three other methods are generated: toString() , hashCode() and equals() .
They all rely on invokedynamic to dynamically invoke the appropriate method
containing the implicit implementation. There is a bootstrap method
ObjectMethods.bootstrap that takes the component names of the record and its
getter methods and generates the methods Their behaviors is consistent with what
https://dzone.com/articles/a-first-look-at-records-in-java-14 9/12
19/1/23, 10:08 A First Look at Records in Java 14 - DZone
getter methods, and generates the methods. Their behaviors is consistent with what
we would expect to have:
Java
1 Person john = new Person("John", "Doe");
2 System.out.println(john.firstName());         // John
3 System.out.println(john.lastName());          // Doe
4 System.out.println(john);                     // Person[firstName=John, lastName=Doe]
5
6 Person jane = new Person("Jane", "Dae");
7 Person johnCopy = new Person("John", "Doe");
8
9 System.out.println(john.hashCode());          // 71819599
10 System.out.println(jane.hashCode());          // 71407578
11 System.out.println(johnCopy.hashCode());      // 71819599
12 System.out.println(john.equals(jane));        // false
13 System.out.println(john.equals(johnCopy));    // true

Adding Member Declarations in Records


We cannot add instance fields to records, which is expected, given that such state should
be part of the components. We can, however, add static fields:

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)

JDK 14: Records, Text Blocks, and More (https://dzone.com/articles/jdk-14-records-


text-blocks-and-more)

Record (Computer Science) Java (Programming Language)

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)

Handling Virtual Threads (/articles/handling-virtual-threads?fromrel=true)

Comparing Flutter vs. React Native (/articles/comparing-flutter-vs-react-native?


fromrel=true)

Common Mistakes to Avoid When Writing SQL Code (/articles/common-mistakes-to-


avoid-when-writing-sql-code?fromrel=true)

https://dzone.com/articles/a-first-look-at-records-in-java-14 12/12

You might also like