Member Declarations
The component fields of a record class are always automatically generated based on the field components specified in the component list. Thus a record class cannot declare any new instance fields in addition to those specified in the component list.
However, new instance methods can be declared in a record class. In Example 5.31, three new instance methods are declared at (8) in the record class to determine the genre of a CD.
Automatic generation of any get method or methods overridden from the Object class (equals(), hashCode(), and toString()) will be suppressed in a record class, if the record class provides an implementation for any of these methods.
In Example 5.31, the CD record class provides an implementation for the title() method at (9) that returns the uppercase version of the string in the title field. This explicit method will be invoked when called by a client to get the value of the title field in a CD record. An explicit get method can be annotated with the @Override annotation to enable validation of its method signature against that of the default get method that would otherwise be generated. Such an explicit get method must fulfill the following criteria:
- It must be an instance method that is declared public.
- It must have no formal parameters or a throws clause.
- Its return type must be the same as the declared type of its corresponding record component.
- It must not be a generic method.
When the object referenced by a field is mutable, its get method can be explicitly implemented to return a copy of the object so that the original object is never modified, maintaining the immutability of the record. As values of individual component fields cannot be changed, a new record with any modified values must be created.
Also, static fields, methods, and initializers (§10.7, p. 545) can be declared. In Example 5.31, the CD record class declares static fields to create some ready-made CD records. Argument values passed in the constructor call to create CD records will be sanitized by the compact constructor at (2) before being assigned to the component fields by the implicit canonical record constructor.
Nested static types can also be declared in a record class (Chapter 9, p. 489). In Example 5.31, the enum type Genre is declared as a static member of the CD record class at (11), and is used in the CD record class.
In Example 5.31, the client class DataUser2 uses some of the explicitly implemented methods in the CD record class. The CD.isOther() method is used at (13) to filter an array of CDs created at (12). The output from the program shows that the values passed in the constructor calls were sanitized.
An uppercase version of the string in the title field is printed when the title() method is explicitly invoked on a CD record. However, note that the automatically generated toString() method, called at (14), does not use the uppercase version of the title. The reason is that the fields are accessed directly by the generated methods in the record class, and not by calling the get methods. The toString() method accesses the title field directly, thereby accessing the original string in the field. In order to use the uppercase version of the string in all contexts, it can be converted to uppercase in the compact constructor by replacing line (4a) with (4b) so that the uppercase version of the string is assigned to the title field—and thereby making the title() method declared at (9) redundant.
Example 5.31 Other Member Declarations in a Record Class
package record.customize;
import java.time.Year;
/** A record class that represents a CD. */
public record CD(String artist, String title, int noOfTracks, // (1)
Year year, Genre genre) {
// Compact canonical record constructor (2)
public CD {
// Sanitize the values passed to the constructor: (3)
artist = artist.strip();
title = title.strip(); // (4a)
// title = title.strip().toUpperCase(); // (4b)
noOfTracks = noOfTracks < 0 ? 0 : noOfTracks;
year = year.compareTo(Year.of(2022)) > 0? Year.of(2022) : year;
genre = genre == null ? Genre.OTHER : genre;
// Cannot explicitly assign to component fields: (5)
// this.artist = artist; // Compile-time error!
}
// A non-canonical record constructor (6)
public CD() {
this(” Anonymous “, ” No title “, 0, Year.of(2022), Genre.OTHER); // (7)
}
// New instance methods: (8)
public boolean isPop() { return this.genre == Genre.POP; }
public boolean isJazz() { return this.genre == Genre.JAZZ; }
public boolean isOther() { return this.genre == Genre.OTHER; }
// Customize a get method: (9)
@Override public String title() {
return this.title.toUpperCase();
}
// Static fields with some ready-made CDs: (10)
public final static CD cd0
= new CD(” Jaav”, “Java Jive”, 8, Year.of(2017), Genre.POP);
public final static CD cd2
= new CD(“Funkies “, ” Lambda Dancing “, 10, Year.of(2024), null);
public final static CD cd4
= new CD(“Genericos”, “Hot Generics”, -5, Year.of(2018), Genre.JAZZ);
// Declare a nested type:
public enum Genre {POP, JAZZ, OTHER} // (11)
}
package record.customize;
public class DataUser2 {
public static void main(String[] args) {
CD[] cdArray = {CD.cd0, CD.cd2, CD.cd4, new CD()}; // (12)
for(int i = 0; i < cdArray.length; ++i) {
CD cd = cdArray[i];
if (cd.isOther()) { // (13)
System.out.println(cd.toString()); // (14)
}
}
System.out.println(“Title: ” + cdArray[1].title()); // (15)
}
}
Output from the program:
Click here to view code image CD[artist=Funkies, title=Lambda Dancing, noOfTracks=10, year=2022, genre=OTHER]
CD[artist=Anonymous, title=No title, noOfTracks=0, year=2022, genre=OTHER]
Title: LAMBDA DANCING
Leave a Reply