Records practice questions

From OCP Java SE 25 (1Z0-831) · 15 questions on this topic

Records practice questions from OCP Java SE 25 (1Z0-831). This pack has 15 questions tagged Records, drawn from its timed mock exams. 8 of them are worked through in full below — the question, every option, why each is right or wrong, and the explanation.

Worked examples for Records

  1. Question 1

    What does this print? ```java public class Main { record Money(long cents) { static Money of(long dollars) { return new Money(dollars * 100); } } public static void main(String[] args) { Money m = Money.of(2); System.out.print(m.cents()); } } ```

    1. A. 2

      Assumes the accessor returned the factory's dollars argument; the factory multiplied by 100 before constructing, so the stored component is 200.

    2. B. 200Correct answer

      The factory computes 2 * 100 = 200 and constructs Money(200); the component-named accessor cents() returns the stored 200.

    3. C. Compilation fails: a record cannot declare a static factory method

      Records may freely declare static members, including static factory methods; only extra instance fields are forbidden.

    4. D. Compilation fails: the accessor must be named getCents()

      Record accessors are named exactly after the component (cents()), never getCents(); a getX-style name is a classic accessor-naming distractor.

    Explanation

    A static factory method is legal on a record because the header fixes only instance state, not static members. The generated accessor is named exactly after its component with no get prefix, so it returns whatever value the constructor stored after the factory's arithmetic ran.

  2. Question 2

    The record `Tag` has a compact constructor that normalises its components, plus a one-argument non-canonical constructor. What is printed? ```java public class Main { record Tag(String name, int weight) { Tag { name = name.strip().toUpperCase(); if (weight < 1) { weight = 1; } } Tag(String name) { this(name, 0); } } public static void main(String[] args) { Tag a = new Tag(" java "); Tag b = new Tag("JAVA", 1); System.out.println(a + " " + a.equals(b)); } } ```

    1. A. Tag[name= java , weight=0] false

      Assumes the compact constructor does not normalise; its body assigns the parameters that are then stored, so the name is stripped and upper-cased.

    2. B. Tag[name=JAVA, weight=0] false

      Forgets that the delegating constructor also runs the compact constructor, which clamps the zero weight up to one.

    3. C. Tag[name=JAVA, weight=1] trueCorrect answer

      The compact constructor normalises the parameters before they are assigned, and the one-argument constructor delegates through it, so the stored values are the upper-cased name and weight one; the record's equals compares components, so the two are equal.

    4. D. Compilation fails

      Assumes the constructors are illegal; a compact constructor plus a delegating non-canonical constructor is valid.

    Explanation

    A compact constructor's body assigns to the parameters, and the implicit field assignments run afterward, so normalisation performed in the body is what gets stored. A non-canonical constructor must delegate with this(...), routing its arguments through the canonical constructor and thus through the same normalisation. A record's generated equals compares all components.

  3. Question 3

    What does this print? ```java public class Main { record Temp(double v) {} public static void main(String[] args) { Temp a = new Temp(Double.NaN); Temp b = new Temp(Double.NaN); Temp c = new Temp(0.0); Temp d = new Temp(-0.0); System.out.print(a.equals(b) + " " + c.equals(d) + " " + (c.v() == d.v())); } } ```

    1. A. true false trueCorrect answer

      A record's generated equals compares double components as by Double.compare (bit-pattern ordering), so NaN equals NaN (first result true) and 0.0 differs from -0.0 (second result false); the third term is a plain == where IEEE 754 gives 0.0 == -0.0 as true — true false true.

    2. B. true false false

      Reads the record semantics correctly but back-projects them onto ==, assuming the operator also distinguishes negative zero; == is numeric, so 0.0 == -0.0 is true.

    3. C. false true true

      The single most common belief — that record equals just does == on each primitive component; that would make NaN unequal to itself and -0.0 equal to 0.0, the exact inverse of both record results.

    4. D. true true true

      Gets NaN right but assumes -0.0 and 0.0 are the same value everywhere; they compare equal numerically but not by Double.compare, so the record's equals separates them.

    Explanation

    Trace: a record's generated `equals` does not compare `double` components with `==`. JLS 25 §8.10.3 specifies that `float` and `double` components are compared as if by `Float.compare`/`Double.compare`, which is bit-pattern ordering rather than IEEE 754 numeric equality. Under `Double.compare`, `NaN` equals `NaN`, so `a.equals(b)` is `true`; and `0.0` and `-0.0` have different bit patterns, so `c.equals(d)` is `false`. The third term is a plain `==` on the two `double` values, and IEEE 754 says `0.0 == -0.0` is `true`. Output: `true false true`. Why the others are wrong: `false true true` is what you get from the single most common belief — that record `equals` just does `==` on each primitive component. That would make `NaN` unequal to itself and `-0.0` equal to `0.0`, i.e. the exact inverse of both record results. `true true true` gets `NaN` right but assumes `-0.0` and `0.0` are "the same value" everywhere. They compare equal numerically but not by `Double.compare`, so the record separates them. `true false false` reads the record's semantics correctly and then wrongly back-projects them onto `==`, assuming the operator also distinguishes negative zero. `==` is numeric: `0.0 == -0.0` is `true`. Exam tip: a record's `equals` is `Double.compare`-based, which is *deliberately* the opposite of `==` on both of IEEE 754's oddities — `NaN` becomes self-equal and the two zeros become distinct. This is what makes records reliable in hash collections (`equals` must be reflexive, and `NaN != NaN` under `==` would break that). The same rule governs `Double.equals` and `Double.valueOf` boxing.

  4. Question 4

    What is the result? ```java public class Main { record Point(int x, int y) { int z; } public static void main(String[] args) { System.out.print(new Point(1, 2)); } } ```

    1. A. Point[x=1, y=2]

      This is what you would get if the field were silently ignored, but the illegal field declaration is rejected, not dropped.

    2. B. Point[x=1, y=2, z=0]

      Assumes the body field becomes a fourth component; only the header defines components, and the generated toString would never include a body field.

    3. C. The code compiles and z defaults to 0

      A non-static instance field is illegal in a record, so there is no compiling program and the field never defaults to 0.

    4. D. Compilation fails: a record may not declare a non-static instance fieldCorrect answer

      A record's state is fixed by its header; declaring an extra non-static instance field is a compile-time error, legal only if the field is made static.

    Explanation

    A record's instance state is defined entirely by its header components, so declaring an additional non-static instance field in the body is a compile-time error. The very same field written as static would compile, since records forbid only extra instance state, not static members.

  5. Question 5

    What does this print? ```java import java.util.*; public class Main { public static void main(String[] args) { record Pair(String key, int val) { int doubled() { return val * 2; } } List<Pair> list = List.of(new Pair("a", 3), new Pair("b", 4)); int sum = 0; for (Pair p : list) sum += p.doubled(); System.out.print(sum); } } ```

    1. A. Compilation fails: a record cannot be declared inside a method body

      Local records are expressly permitted; modeling intermediate data inside a method is exactly what they are for.

    2. B. 14Correct answer

      The local record's doubled() returns 6 and 8 for the two pairs, and the loop sums them to 14.

    3. C. 7

      Sums the raw val components (3 + 4) and forgets that doubled() multiplies each by 2.

    4. D. Compilation fails: a local record cannot declare an instance method

      A local record may declare instance methods, static members, and its own constructors, just like a nested or top-level record; only capturing enclosing locals is disallowed.

    Explanation

    A local record declared inside a method is legal and may carry instance methods just like any nested or top-level record; only capturing the enclosing method's variables is disallowed, since a local record is implicitly static. Here each element's method doubles its value component, so the loop sums the doubled values rather than the raw ones.

  6. Question 6

    What is the result of compiling and running this code? ```java public class Main { public record Box(int size) { private Box(int size) { this.size = size; } } public static void main(String[] args) { System.out.print(new Box(5).size()); } } ```

    1. A. 5

      Assumes the code runs; it never compiles because the canonical constructor's access is narrower than the record's.

    2. B. Compilation fails: a record cannot declare an explicit canonical constructor

      A record may declare an explicit canonical constructor with the full parameter list; the problem here is only its access level, not its existence.

    3. C. Compilation fails: the canonical constructor is less accessible than the recordCorrect answer

      The explicit canonical constructor of a public record must be public; declaring it private narrows access, which javac rejects as attempting stronger access privileges.

    4. D. 0

      Imagines a default value, but no instance is ever constructed because the code fails to compile.

    Explanation

    An explicit canonical constructor must be at least as accessible as the record class itself. Declaring it with a more restrictive modifier than the public record narrows the access, which the compiler rejects — mirroring the general rule that you may widen access but never narrow it.

  7. Question 7

    What does this print? ```java public class Main { record Data(int[] vals) {} public static void main(String[] args) { Data a = new Data(new int[]{1, 2, 3}); Data b = new Data(new int[]{1, 2, 3}); System.out.print(a.equals(b)); } } ```

    1. A. falseCorrect answer

      The generated equals compares the int[] component with the array's own equals, which is identity-based; the two arrays are distinct objects, so the result is false.

    2. B. true

      Assumes the generated equals compares array contents; it uses the array's own equals, which is identity-based, not content comparison.

    3. C. Compilation fails: int[] is not a permitted record component type

      An array is a perfectly legal record component type; nothing about the declaration fails.

    4. D. true only when the arrays are the same length

      Length is irrelevant; two different array objects are unequal regardless of their contents or lengths.

    Explanation

    A record's generated equals compares each component using that component's own equals method. An array component inherits identity-based equals from Object, so two records holding different array instances are unequal even when the array contents match; value equality over an array component requires a custom override or using a List.

  8. Question 8

    What does this print? ```java import java.util.*; public class Main { record Coord(int x, int y) {} public static void main(String[] args) { Set<Coord> seen = new HashSet<>(); seen.add(new Coord(1, 2)); seen.add(new Coord(1, 2)); Map<Coord, String> map = new HashMap<>(); map.put(new Coord(3, 4), "hi"); System.out.print(seen.size() + " " + map.get(new Coord(3, 4))); } } ```

    1. A. Compilation fails: a record must override hashCode to be used as a hash key

      Invents a rule; overriding hashCode in a record is permitted but never required, and nothing about HashMap demands it.

    2. B. 2 null

      The answer you get if you believe records inherit Object's identity-based equals/hashCode like a plain class — the classic hand-written-key bug; records generate value-based equals/hashCode, so they are the fix for exactly that.

    3. C. 1 null

      Assumes equals is generated (so the set dedupes) but that a HashMap lookup still needs the identical key object; the generated hashCode is derived from the same components as equals, so a fresh Coord(3, 4) lands in the same bucket and finds the stored value.

    4. D. 1 hiCorrect answer

      A record derives equals and hashCode from all of its components, so two separately built Coord(1, 2) are equal and hash alike — HashSet rejects the duplicate (size 1) and a fresh Coord(3, 4) retrieves the stored value, giving `1 hi`.

    Explanation

    Trace: a record automatically gets `equals` and `hashCode` derived from all of its components, so two separately constructed `Coord(1, 2)` instances are equal *and* hash alike. `HashSet` therefore rejects the second `add` as a duplicate and `seen.size()` is `1`. For the same reason a freshly built `new Coord(3, 4)` lands in the same bucket as the key that was stored and compares equal to it, so `map.get(...)` returns `"hi"`. The output is `1 hi`. Why the others are wrong: `2 null` is the answer you get if you believe records inherit `Object`'s identity-based `equals`/`hashCode` like a plain class with no overrides — the classic reason a hand-written key class fails. Records are the fix for exactly that bug. `1 null` splits the difference: it assumes `equals` is generated (so the set dedupes) but that a `HashMap` lookup still needs the identical key object. Any lookup that finds nothing does so because the *hash* disagrees, and the generated `hashCode` is derived from the same components as `equals`, so the two can never disagree here. `Compilation fails: a record must override hashCode to be used as a hash key` invents a rule. Overriding `hashCode` in a record is permitted but never required, and nothing about `HashMap` demands it. Exam tip: records are correct-by-construction hash keys — value equality over every component, with a `hashCode` consistent with it. The trap is a record with an array component: array `equals` is identity, so `record Data(int[] vals)` breaks the contract and two `Data` holding `{1, 2, 3}` are *not* equal.

Practise all 15 Records questions

OCP Java SE 25 has the full set, inside timed mock exams that mirror real exam conditions — every question with a worked explanation.

Open OCP Java SE 25

Other topics in this pack