Augmenting Basic Record Class Declaration – Object-Oriented Programming

Augmenting Basic Record Class Declaration

In the rest of this section, we explore how the basic declaration of a record class can be augmented and customized. The general syntax of a record class is shown below.

Click here to view code image

access_modifier
 record
record_name
(
component_list
)
optional_implements_clause
 {
optional_constructor_declarations
optional_member_declarations
}

The basic declaration of a record class can be augmented with an implements clause in order to implement any interfaces. Constructors can be customized, as can the get methods corresponding to the component fields. New instance methods can be declared, as can static members and initializers, but new instance fields and initializers are not allowed in the record body.

Record Constructors

In this section we discuss three kinds of constructors that can be specified in a record class declaration:

  • A normal canonical record constructor, if declared, supersedes the implicit canonical record constructor.
  • If a normal canonical record constructor is not specified, a compact canonical record constructor can be declared. In this case, the implicit canonical record constructor is generated. Note that either the normal canonical record constructor or the compact canonical record constructor can be specified, but not both.
  • Any number of non-canonical record constructors can be specified, whether or not any canonical constructor is provided.
Normal Canonical Record Constructor

In a basic record class declaration, the compiler generates the implicit canonical record constructor discussed earlier to ensure that component fields of a record are initialized properly. This canonical record constructor can be implemented explicitly when there is a need to process the argument values before they are assigned to the component fields. This explicit canonical record constructor is called the normal canonical record constructor as its declaration resembles the constructor of a normal class. If a record class implements the normal canonical record constructor, the implicit counterpart is not generated.

The normal canonical constructor must have the same parameter list as the implicit canonical record constructor, in name, type, and order. In the constructor, the component fields must be accessed with the this reference to distinguish them from the parameter names, and all component fields must be initialized in the constructor. In Example 5.29, the record class CD provides an implementation of the normal canonical constructor at (2). The parameter values are sanitized at (3) before being assigned to the component fields at (4). Running the DataUser class in Example 5.28 with the record class CD in Example 5.29 produces the same results.

Here are a few other restrictions to note regarding the normal canonical constructor:

  • It must be at least as accessible as the record class. For example, for a top-level record class that has public accessibility, it must be declared public.
  • It cannot be generic (§11.7, p. 593), or have a throws clause in its header (§7.5, p. 388). In other words, any checked exception thrown by the constructor must be handled in the body of the constructor.
  • It cannot invoke another record constructor with the this() expression to chain constructors locally (p. 209), as is the case with normal constructors.

Example 5.29 Normal Canonical Record Constructor

Click here to view code image

package record.constructors.canonical;
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) {
  // Normal canonical record constructor                              // (2)
  public CD(String artist, String title, int noOfTracks, Year year, Genre genre) {
    // Sanitize the parameter values:                                    (3)
    artist = artist.strip();
    title = title.strip();
    noOfTracks = noOfTracks < 0 ? 0 : noOfTracks;
    year =  year.compareTo(Year.of(2022)) > 0? Year.of(2022) : year;
    genre = genre == null ? Genre.OTHER : genre;
    // Initialize all component fields:                                   (4)
    this.artist     = artist;
    this.title      = title;
    this.noOfTracks = noOfTracks;
    this.year       = year;
    this.genre      = genre;
  }
}


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *