Friday, December 2, 2022

Quiz yourself: What you can and can’t do with Java records

Java records are implicitly final. What does that mean in practice?


What can you declare in the body block of a Java record? Choose two.

Oracle Java, Java Exam, Java Prep, Java Preparation, Java Tutorial and Mateirals, Java Gudies, Java Materials

A. An instance variable
B. An instance method
C. An instance initialization block
D. A no-argument constructor

Answer. One of the goals of records is to approximate immutable data-carrier types. To this end, all the data elements of a record are implicitly final. Note that the record does not prevent mutation of a mutable object referred to through a final reference, however; therefore a record only approximates an immutable data carrier.

Option A is incorrect: You may not declare your instance variables in the body of a record. An example of the record syntax looks like the following:

record Car(int seats, String color) {}

Given this code, execution of new Car(5, "Red") results in an immutable object that has storage for an int value named seats and a String reference value named color. You might observe that the elements named seats and color are fields, which are commonly called instance variables.

However, for two reasons, option A is not a correct answer to this exam question. First, and most importantly, those fields are not declared in the body block of the record. Instead, they are outside the curly braces. The second, weaker, objection is that of nomenclature. Although reflection reports these as private final fields if you invoke getDeclaredFields on the Car.class object, the Java Language Specification does not refer to them this way. Rather it considers these fields to be record components.

Note that although you cannot declare instance fields in a record using the syntax used for a class, you can define class variables (that is, static variables) in a Java record.

Option B is correct: You can declare custom instance methods in a record. The record type automatically creates accessor methods for the record components, but it’s possible to define these explicitly if desired.

It’s also possible to replace the implementations of other autogenerated methods such as equals(Object o) and hashCode().

Beyond that, you can define arbitrary methods (both instance and static) according to your needs. Further, you can declare nested classes, interfaces, and other records inside a Java record.

Option C is incorrect: A record may not have an instance initialization block, but it does provide a somewhat related syntax known as a compact constructor. The compact constructor lets you interact with the initialization values prior to their being assigned to their final storage locations.

The compact constructor can also throw an exception if the construction is to be rejected.

Notably, the compact constructor cannot assign values to the final storage locations for the record components—that must be done by autogenerated code that is invoked after the compact constructor.

Option D is correct: You may declare your own constructors. A constructor with an argument type sequence matching the type sequence of the record components is called the canonical constructor. The canonical constructor is not usually coded explicitly, and if it isn’t, it will be generated automatically. The canonical constructor must assign values to the record components.

Constructors with other argument type sequences must delegate, using the this(...) delegation mechanism, in such a way that they ultimately call the canonical constructor. Since the canonical constructor must assign the record component values, noncanonical constructors cannot do this, since that would constitute multiple assignments to a final variable.

In other words, the first line of any noncanonical constructor must be an invocation of this(...), and the last element in the resulting chain must invoke the canonical constructor, as follows:

Copy code snippet
Copied to ClipboardError: Could not CopyCopied to ClipboardError: Could not Copy
record Time(int hrs, int min) {
    Time() {        // no-arg, noncanonical constructor
        this(0);    // delegates to the constructor below
    }
    Time(int hrs) { // another noncanonical constructor
                    // delegates to the autogenerated canonical constructor
        this(hrs, 0);
    }
}

Conclusion. The correct answers are options B and D.

Source: oracle.com

Related Posts

0 comments:

Post a Comment