CertSafari

    Free Oracle Java SE 21 Developer Professional Sample Questions

    35 free sample questions from our bank of 345+, covering every exam domain, with answers and detailed explanations. Updated September 2026.

    Domain 1: Handling Date, Time, Text, Numeric and Boolean Values

    Subdomain 1.2: Manipulate text, including text blocks, using String and StringBuilder classes

    1.What is printed by the following code? ```java String s1 = "Java"; String s2 = "Java"; String s3 = new String("Java"); String s4 = s3.intern(); System.out.println((s1 == s2) + " " + (s1 == s3) + " " + (s1 == s4)); ```

    1. A.true false true
    2. B.true true true
    3. C.false false true
    4. D.true false false
    Show answer & explanation

    Correct answer: Atrue false true

    • A. `s1` and `s2` are both string literals, so the compiler resolves them to the same interned reference in the string pool, making `s1 == s2` true. `s3` is created with `new String(...)`, producing a distinct heap object, so `s1 == s3` is false; calling `intern()` on `s3` returns the pooled reference for "Java", which is the same object as `s1`, making `s1 == s4` true.
    • B. This assumes `new String("Java")` also produces the pooled reference, but the `new` keyword explicitly forces allocation of a separate heap object distinct from anything in the string pool. `s1 == s3` must therefore be false, not true.
    • C. This assumes string literals are not automatically pooled, but the Java compiler always interns literal strings, so `s1` and `s2` refer to the identical pooled object and their comparison must be true, not false.
    • D. This correctly identifies that `s1 == s3` is false but incorrectly assumes `intern()` returns a fresh object rather than the existing pooled reference. `intern()` specifically looks up and returns the canonical pooled instance, so `s1 == s4` must be true.

    Subdomain 1.2: Manipulate text, including text blocks, using String and StringBuilder classes

    2.Which of the following statements about escape sequences used inside text blocks are correct? (Select all that apply.)(Select 3)

    1. A.The `\s` escape represents a single space character and prevents that trailing space from being stripped as incidental whitespace.
    2. B.A backslash placed immediately before a line terminator suppresses that line break, joining the current line with the next one.
    3. C.Standard escapes such as `\n` and `\t` are disabled inside text blocks because line structure is already preserved automatically.
    4. D.The `\s` escape may only appear as the first character of a line, never at the end.
    5. E.Every line inside a text block must end with an explicit `\n` escape, or the resulting string will contain no line breaks at all.
    6. F.The minimum incidental indentation is calculated only from the first content line, ignoring all other lines including the closing delimiter line.
    7. G.Three consecutive double-quote characters can appear inside the body of a text block as long as at least one of them is escaped, for example `\"""`.
    Show answer & explanation

    Correct answers: A, B, GThe `\s` escape represents a single space character and prevents that trailing space from being stripped as incidental whitespace.; A backslash placed immediately before a line terminator suppresses that line break, joining the current line with the next one.; Three consecutive double-quote characters can appear inside the body of a text block as long as at least one of them is escaped, for example `\"""`.

    • A. The `\s` escape is interpreted as a plain space character during the final escape-processing step of text block compilation, after incidental trailing whitespace has already been stripped. Placing it at the end of a line preserves spaces that would otherwise be removed, since the line no longer ends in raw whitespace once the escape sequence is present.
    • B. A trailing backslash immediately followed by a line terminator tells the compiler to omit that specific line terminator from the resulting string, effectively continuing the text onto the next source line. This is commonly used to keep long lines readable in source code without introducing an actual line break in the value.
    • C. Standard character escapes remain fully functional inside text blocks and are processed the same way as in ordinary string literals. Text blocks add new escapes like `\s` on top of the existing ones rather than disabling any of them.
    • D. The `\s` escape can appear anywhere within a line, not just at the start; its most common use is specifically at the end of a line to preserve trailing spaces. There is no restriction limiting it to the first character.
    • E. Text blocks automatically insert a line terminator after each source line as part of incidental whitespace processing, so explicit `\n` escapes are not required to produce multi-line output. Line breaks come from the physical line structure of the source text block itself.
    • F. The incidental indentation is determined by examining the leading whitespace of every non-blank content line as well as the line containing the closing delimiter, then taking the smallest value found. Looking only at the first line would produce incorrect results whenever a later line is indented less.
    • G. Because an unescaped run of three double quotes would be interpreted as the closing delimiter, embedding literal triple quotes inside the body requires escaping at least one of the three quote characters. This lets the sequence appear as ordinary text rather than terminating the text block.

    Subdomain 1.1: Use primitives and wrapper classes

    3.Given the following code: ```java int i = 5; double d = 2.5; System.out.println(true ? i : d); ``` What is printed?

    1. A.5 because the conditional operator keeps the type of the chosen branch
    2. B.5.0 because binary numeric promotion converts both operands to double
    3. C.2.5 because the second operand always determines the result type
    4. D.Compilation fails because the two branches have different types
    5. E.5 because int has higher precedence than double in a conditional expression
    Show answer & explanation

    Correct answer: B5.0 because binary numeric promotion converts both operands to double

    • 5 because the conditional operator keeps the type of the chosen branch. When both branches of a conditional expression are numeric but of different types, the compiler applies binary numeric promotion to the whole expression rather than preserving the chosen branch's original type.
    • 5.0 because binary numeric promotion converts both operands to double. Since one branch is int and the other is double, the conditional expression's type is promoted to double, so the selected int value 5 is converted to 5.0 before printing.
    • 2.5 because the second operand always determines the result type. The second operand's type does not automatically win; both branches are combined through numeric promotion regardless of which branch is actually selected at runtime.
    • Compilation fails because the two branches have different types. Mixing int and double in a conditional expression is legal because numeric promotion rules define a common result type, so this compiles without error.
    • 5 because int has higher precedence than double in a conditional expression. There is no precedence ranking between int and double here; numeric promotion always widens the narrower type, so double, not int, wins the promotion.

    Subdomain 1.1: Use primitives and wrapper classes

    4.Given the following code: ```java int x = Integer.MAX_VALUE; x = x + 1; System.out.println(x); ``` What is printed?

    1. A.2147483648 because int silently promotes to long during the addition
    2. B.-2147483648 because the addition overflows and wraps around via two's complement
    3. C.A compilation error occurs since Math.addExact is required for boundary values
    4. D.An ArithmeticException is thrown at runtime because the result exceeds int range
    5. E.0 because overflow always resets an int variable back to its default value
    Show answer & explanation

    Correct answer: B-2147483648 because the addition overflows and wraps around via two's complement

    • 2147483648 because int silently promotes to long during the addition. Java does not automatically promote int arithmetic to long; the operation stays within 32-bit int arithmetic and overflows instead of widening.
    • -2147483648 because the addition overflows and wraps around via two's complement. Adding 1 to Integer.MAX_VALUE overflows the 32-bit signed int range and wraps around to Integer.MIN_VALUE due to two's complement representation, silently, with no exception.
    • A compilation error occurs since Math.addExact is required for boundary values. The plain `+` operator compiles and runs fine on boundary values; Math.addExact is only needed when overflow detection via an exception is desired.
    • An ArithmeticException is thrown at runtime because the result exceeds int range. Ordinary arithmetic operators never throw on overflow; only the `Exact` methods in Math, such as addExact, throw ArithmeticException on overflow.
    • 0 because overflow always resets an int variable back to its default value. Overflow does not reset a variable to a default value; it wraps around according to two's complement rules, producing Integer.MIN_VALUE here.

    Subdomain 1.3: Manipulate date, time, duration, period, instant and time-zone objects including daylight saving time using Date-Time API

    5.Which statements about java.time.Instant are correct? (Choose 3)(Select 3)

    1. A.Instant.now().truncatedTo(ChronoUnit.DAYS) sets the time-of-day fields to midnight while keeping the same UTC date.
    2. B.Instant supports the plus(Duration) method to add an exact number of seconds and nanoseconds to it.
    3. C.ChronoUnit.DAYS.between(instant1, instant2) computes the number of complete 24-hour periods between two instants.
    4. D.Instant.now().atZone(ZoneId.systemDefault()) is not valid because Instant cannot be combined with a ZoneId at all.
    5. E.Instant implements the same comparison interface as LocalDate and can be compared directly to LocalDate values.
    6. F.Calling Instant.now().plusDays(1) adjusts the calendar date by one day in the system default time zone.
    Show answer & explanation

    Correct answers: A, B, CInstant.now().truncatedTo(ChronoUnit.DAYS) sets the time-of-day fields to midnight while keeping the same UTC date.; Instant supports the plus(Duration) method to add an exact number of seconds and nanoseconds to it.; ChronoUnit.DAYS.between(instant1, instant2) computes the number of complete 24-hour periods between two instants.

    • A. truncatedTo with ChronoUnit.DAYS zeroes out everything smaller than a day, leaving the instant at the start of its UTC day; Instant has no time-zone concept, so this midnight is always expressed in UTC.
    • B. Instant is designed around exact elapsed time, so plus(Duration) simply adds the specified seconds and nanoseconds to the underlying epoch value without any calendar interpretation.
    • C. Because Instant has no calendar fields, ChronoUnit.DAYS.between treats a day as a fixed 24-hour block of elapsed time and counts how many such blocks fit between the two instants.
    • D. atZone(ZoneId) is precisely the supported way to convert an Instant into a ZonedDateTime, combining the instant with zone rules to derive local fields; this conversion is valid and commonly used.
    • E. Instant and LocalDate belong to unrelated parts of the temporal type hierarchy and are not directly comparable to each other; Instant models an elapsed-time point, not a calendar date.
    • F. Instant has no plusDays method because it has no notion of a calendar day tied to a time zone; date-based arithmetic like this belongs to zone-aware or local types, not to Instant.

    Subdomain 1.3: Manipulate date, time, duration, period, instant and time-zone objects including daylight saving time using Date-Time API

    6.A developer formats a ZonedDateTime in "America/Los_Angeles" using two different pattern letters: ``` ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("America/Los_Angeles")); String a = zdt.format(DateTimeFormatter.ofPattern("z")); String b = zdt.format(DateTimeFormatter.ofPattern("V")); ``` Which best describes the outputs `a` and `b`?

    1. A.`a` produces a short zone name such as PST or PDT, while `b` produces the zone ID such as America/Los_Angeles.
    2. B.`a` and `b` both produce the numeric offset such as -08:00, with no difference between the two outputs.
    3. C.`a` produces the zone ID such as America/Los_Angeles, while `b` produces a short zone name such as PST.
    4. D.`a` throws an exception because the pattern letter z is not a recognized formatter letter, while `b` succeeds normally.
    5. E.`a` produces the localized GMT-style format such as GMT-08:00, while `b` produces that same value.
    Show answer & explanation

    Correct answer: A`a` produces a short zone name such as PST or PDT, while `b` produces the zone ID such as America/Los_Angeles.

    • A. The pattern letter z formats a short, human-readable zone name like PST or PDT depending on the date, while the pattern letter V is defined to output the full zone ID string such as America/Los_Angeles.
    • B. Neither pattern letter is defined to produce a numeric offset by itself; that behavior belongs to pattern letters like x, X, or Z, so this description does not match z or V.
    • C. This swaps the actual behavior of the two pattern letters: z is the short zone-name letter and V is the zone-ID letter, not the other way around.
    • D. The pattern letter z is a valid and commonly used zone-name symbol in DateTimeFormatter, so formatting with it succeeds rather than throwing an exception.
    • E. The localized GMT offset format is produced by the pattern letter O, not by z or V, so neither of these two outputs matches a GMT-style string.

    Domain 2: Controlling Program Flow

    Subdomain 2.1: Create program flow control constructs including if/else, switch statements and expressions, loops, and break and continue statements

    7.Which switch block is legal in Java 21?

    1. A.```java switch (x) { case 1 -> System.out.println("one"); case 2 -> System.out.println("two"); default -> System.out.println("other"); } ```
    2. B.```java switch (x) { case 1 -> System.out.println("one"); case 2: System.out.println("two"); default: System.out.println("other"); } ```
    3. C.```java switch (x) { case 1 -> yield 1; default -> yield 0; } ```
    4. D.```java switch (x) { case 1 -> { System.out.println("one"); } case 2 -> (x + 1); default -> System.out.println("other"); } ```
    Show answer & explanation

    Correct answer: A```java switch (x) { case 1 -> System.out.println("one"); case 2 -> System.out.println("two"); default -> System.out.println("other"); } ```

    • A. Every label in this switch block uses the arrow form, which is a legal, consistent style that the grammar permits without mixing label kinds.
    • B. This mixes an arrow-labeled rule with colon-labeled statement groups in the same switch block, which the grammar forbids; a block must use either all arrow labels or all colon labels.
    • C. This switch is used as a statement, not assigned to a variable, so it is not a switch expression; yield is only valid when the enclosing switch produces a value, making this construct illegal here.
    • D. The rule `case 2 -> (x + 1);` is not a valid statement expression on its own; a parenthesized arithmetic expression cannot stand alone as a statement, so this fails to compile.

    Domain 3: Using Object-Oriented Concepts in Java

    Subdomain 3.1: Declare and instantiate Java objects including nested class objects, and explain the object life-cycle including creation, reassigning references, and garbage collection

    8.Consider the following code: ```java class Cache { private byte[] largeData = new byte[1_000_000]; class Snapshot { String label; Snapshot(String label) { this.label = label; } } } public class Test { static Cache.Snapshot held; static void register() { Cache cache = new Cache(); held = cache.new Snapshot("first"); } public static void main(String[] args) { register(); // point P } } ``` Which statements about point P are correct? (Choose 3.)(Select 3)

    1. A.Because `held` is a `static` field, the JVM exempts whatever it references from garbage collection eligibility tracking altogether.
    2. B.The 1,000,000-byte array `largeData` cannot be garbage collected at point P, because it is reachable through the surviving `Cache` instance.
    3. C.Declaring `Snapshot` as a `static` nested class instead of a non-static inner class would remove the implicit reference to `Cache`, letting the `Cache` instance become eligible once `held` no longer holds it.
    4. D.The local variable `cache` keeps the `Cache` instance reachable after `register` returns, because local variables retain their bindings for the lifetime of the program.
    5. E.Non-static inner classes never retain a reference to their enclosing instance once the method that created them has returned.
    6. F.At point P, the `Cache` instance created inside `register` remains reachable, because the `Snapshot` object stored in `held` implicitly references its enclosing `Cache` instance.
    7. G.The `Snapshot` object referenced by `held` is eligible for garbage collection at point P, because `cache` went out of scope when `register` returned.
    Show answer & explanation

    Correct answers: B, C, FThe 1,000,000-byte array `largeData` cannot be garbage collected at point P, because it is reachable through the surviving `Cache` instance.; Declaring `Snapshot` as a `static` nested class instead of a non-static inner class would remove the implicit reference to `Cache`, letting the `Cache` instance become eligible once `held` no longer holds it.; At point P, the `Cache` instance created inside `register` remains reachable, because the `Snapshot` object stored in `held` implicitly references its enclosing `Cache` instance.

    • A. A `static` field is itself a garbage collection root, but the objects it references are still subject to ordinary reachability tracking; nothing about being referenced from a static field exempts an object from collection.
    • B. `largeData` is an instance field of the still-reachable `Cache` object, so it is reachable by the same chain that keeps `Cache` itself alive, and it cannot be collected until that chain is broken.
    • C. A static nested class carries no implicit outer reference, so a `Snapshot` declared that way would not keep the `Cache` instance reachable, letting `Cache` become eligible once nothing else refers to it.
    • D. Local variables only keep their referents reachable while the method invocation that declared them is on the call stack; once `register` returns, `cache` no longer exists as a root.
    • E. The implicit outer reference is stored as a field on the inner class instance itself and persists for as long as that inner instance exists, independent of whether the method that created it has returned.
    • F. Every non-static inner class instance carries an implicit reference to the enclosing instance that created it, so as long as the `Snapshot` object is reachable via `held`, its `Cache` instance stays reachable too.
    • G. `held` still refers to the `Snapshot` object at point P, so it remains reachable regardless of whether the local variable `cache` that originally created it has gone out of scope.

    Subdomain 3.2: Create classes and records, and define and use instance and static fields and methods, constructors, and instance and static initializers

    9.```java class Shape { Shape() { report(); } void report() { System.out.println("shape-default"); } } class Square extends Shape { private int sides = 4; @Override void report() { System.out.println("sides=" + sides); } } public class Main { public static void main(String[] args) { new Square(); } } ``` What is printed when `main` runs?

    1. A.sides=0
    2. B.sides=4
    3. C.shape-default
    4. D.Does not compile
    Show answer & explanation

    Correct answer: Asides=0

    • A. Square's implicit constructor calls super(), and Shape's constructor invokes the overridden report(), which runs using Square's dynamic dispatch before the sides field initializer has executed, so sides still holds its default value of 0.
    • B. The sides field initializer only runs after the superclass constructor returns, but report() is called from inside Shape's constructor, before that initializer has a chance to run, so 4 is not yet assigned.
    • C. Dynamic dispatch means the overridden version in Square runs even when invoked from the superclass constructor, so the original Shape implementation never executes here.
    • D. This code compiles cleanly: Square has an implicit no-arg constructor, @Override correctly matches report()'s signature, and there is no syntax or type error present.

    Subdomain 3.4: Understand variable scopes, apply encapsulation, and create immutable objects

    10.A payroll application defines an immutable `Salary` class holding a `BigDecimal amount` field, with a constructor that assigns the parameter directly to the field, and a getter that returns the field directly. A code reviewer flags this design as still fully safe for immutability purposes despite skipping defensive copying of `amount`. Why is the reviewer's assessment correct in this specific case?

    1. A.`BigDecimal` is itself an immutable class, so there is no risk of a caller mutating the shared referenced object through either the constructor argument or the returned reference
    2. B.Defensive copying is only ever needed for `String` fields, since `String` is the sole class in the standard library capable of being mutated after construction
    3. C.The field is accessed through a getter method rather than directly, and any access through a getter method is inherently safe regardless of the referenced object's mutability
    4. D.`BigDecimal` values are always passed by value in Java, so the field and the caller's variable never actually reference the same object in memory
    Show answer & explanation

    Correct answer: A`BigDecimal` is itself an immutable class, so there is no risk of a caller mutating the shared referenced object through either the constructor argument or the returned reference

    • A. This is correct: defensive copying exists specifically to protect against a shared mutable object being changed after the fact; since `BigDecimal` instances cannot be mutated once created, storing and returning the same reference introduces no risk to the `Salary` object's immutability.
    • B. This is incorrect because many classes besides `String` are mutable (e.g. `Date`, `ArrayList`), and conversely `String` itself is immutable in Java, so the premise about which classes need defensive copies is backwards.
    • C. This is incorrect because a getter returning a reference to a mutable object is not inherently safe; the safety in this scenario comes specifically from `BigDecimal`'s own immutability, not from the mere presence of a getter method.
    • D. This is incorrect because object references, including `BigDecimal` references, are still reference values in Java; the field and a caller's variable can indeed refer to the identical heap object, it's just that mutating that object isn't possible.

    Subdomain 3.4: Understand variable scopes, apply encapsulation, and create immutable objects

    11.A senior engineer is reviewing a candidate's `Point` class meant to be immutable: ```java public final class Point { private final double x; private final double y; public Point(double x, double y) { this.x = x; this.y = y; } public Point translate(double dx, double dy) { this.x += dx; this.y += dy; return this; } public double getX() { return x; } public double getY() { return y; } } ``` What is the correct assessment of this class, and how should `translate` be fixed to preserve immutability?

    1. A.The class fails to compile because `translate` reassigns the `final` fields `x` and `y`; it should instead return a brand-new `Point` built from `x + dx` and `y + dy`, leaving the original object's fields untouched
    2. B.The class compiles and behaves correctly as an immutable type, because `translate` returns `this`, and any method returning `this` automatically preserves immutability regardless of what happens inside the method body
    3. C.The class fails to compile only because `getX` and `getY` are missing the `final` modifier on the methods themselves; adding `final` to both accessor methods would resolve the issue
    4. D.The class compiles successfully and is immutable as written, because reassigning a `final` field is permitted as long as the reassignment happens inside a method of the same class rather than from outside
    Show answer & explanation

    Correct answer: AThe class fails to compile because `translate` reassigns the `final` fields `x` and `y`; it should instead return a brand-new `Point` built from `x + dx` and `y + dy`, leaving the original object's fields untouched

    • A. This is correct: `x += dx` and `y += dy` are compound assignments to `final` fields outside of the constructor, which the compiler rejects; the fix is to compute the translated coordinates and return them wrapped in a new `Point` instance, leaving `x` and `y` on the original object untouched.
    • B. This is incorrect because returning `this` has no bearing on whether the method's body is legal; the compile error caused by reassigning `final` fields occurs regardless of what the method returns.
    • C. This is incorrect because ordinary instance methods do not need to be declared `final` for a class to be immutable, and adding `final` to `getX`/`getY` would not address the actual compile error, which is the illegal field reassignment in `translate`.
    • D. This is incorrect because `final` fields can only be assigned once, during construction (or, for instance fields, within instance initializers or the constructor); no exception exists that allows reassignment merely because the reassigning code is inside the same class.

    Subdomain 3.3: Implement overloaded methods, including var-arg methods

    12.Given: ```java class Sizer { static void size(long x) { System.out.println("long"); } static void size(int... x) { System.out.println("varargs"); } } ``` What happens when `Sizer.size(3);` is executed?

    1. A.`varargs` prints because the compiler prefers the varargs overload whenever the argument count exactly matches the number of declared varargs elements.
    2. B.`long` prints because widening a primitive `int` to `long` is a strict invocation match, which the compiler resolves before considering any variable-arity overload.
    3. C.The call fails to compile because both overloads can accept a single `int` argument, and the compiler cannot rank widening against varargs expansion.
    4. D.`long` prints, but only because the varargs parameter's element type does not match `long`, not because of any phase-based resolution order.
    Show answer & explanation

    Correct answer: B`long` prints because widening a primitive `int` to `long` is a strict invocation match, which the compiler resolves before considering any variable-arity overload.

    • A. Argument count matching is not the deciding factor here; phase order is. A candidate reachable through widening in the strict phase is chosen before the compiler ever considers a variable-arity candidate, regardless of count.
    • B. This is correct because widening `int` to `long` is allowed in the strict invocation phase without boxing or varargs, so `size(long)` is found applicable first and is selected over the varargs overload.
    • C. There is no ambiguity because resolution stops once a candidate is found applicable in an earlier phase; the varargs candidate in the later phase is never even considered once the widening match succeeds.
    • D. The element type mismatch is not why `long` prints; the reason is that phase-based resolution finds and selects the widening match before variable-arity invocation is ever attempted, regardless of element types involved.

    Subdomain 3.6: Create and use interfaces, identify functional interfaces, and utilize private, static, and default interface methods

    13.Consider the following interface declarations: ```java // Interface P interface P { void run(); } // Interface Q interface Q { void run(); default void log() {} } // Interface R interface R { void run(); void stop(); } // Interface S interface S { boolean equals(Object obj); void run(); } // Interface T interface T { static void run() {} } ``` Which of these interfaces are valid functional interfaces? (Select all that apply.)(Select 3)

    1. A.Interface `P` is a functional interface because it declares exactly one abstract method.
    2. B.Interface `Q` is not a functional interface because the added `default` method counts as a second abstract method.
    3. C.Interface `Q` is a functional interface because default methods do not count toward the abstract method total.
    4. D.Interface `R` is a functional interface because both `run` and `stop` are abstract methods that a single lambda body can implement together.
    5. E.Interface `S` is a functional interface because `equals` duplicates a public method already declared in `Object` and is therefore excluded from the abstract method count.
    6. F.Interface `T` is a functional interface because it declares a `static` method that a lambda expression can be assigned to.
    Show answer & explanation

    Correct answers: A, C, EInterface `P` is a functional interface because it declares exactly one abstract method.; Interface `Q` is a functional interface because default methods do not count toward the abstract method total.; Interface `S` is a functional interface because `equals` duplicates a public method already declared in `Object` and is therefore excluded from the abstract method count.

    • A. `P` declares only the single abstract method `run` with no other methods, which is precisely the minimal shape of a functional interface.
    • B. Default methods are never counted as abstract methods since they already carry an implementation, so adding `log` to `Q` does not disqualify it from being a functional interface.
    • C. Because a default method supplies its own body, it is excluded from the abstract method count, leaving `run` as the only abstract method and making `Q` a valid functional interface.
    • D. A lambda expression implements exactly one abstract method, and `R` declares two independent abstract methods, `run` and `stop`, so no single lambda body can satisfy both and `R` cannot be a functional interface.
    • E. Abstract methods that match the signature of a public method already found on `Object`, such as `equals(Object)`, are excluded when counting abstract methods for the functional interface check, leaving only `run` and making `S` a valid functional interface.
    • F. A lambda expression can only target an abstract instance method, and `T` declares no abstract method at all, only a static one, so there is nothing for a lambda to implement and `T` is not a functional interface.

    Subdomain 3.5: Implement inheritance, including abstract and sealed types as well as record classes

    14.Which statement about `abstract` classes in Java is correct?

    1. A.An abstract class cannot be instantiated directly, but it may declare constructors, concrete methods, and instance fields that are inherited and used by its concrete subclasses.
    2. B.An abstract class cannot declare any constructors, since constructors are only permitted in classes that can be instantiated directly.
    3. C.An abstract class must declare at least one abstract method, or the compiler rejects the `abstract` modifier as unnecessary.
    4. D.An abstract class cannot be extended by another abstract class; only a concrete, non-abstract class may extend an abstract class.
    5. E.An abstract class automatically becomes `sealed` unless it explicitly declares itself `non-sealed`, restricting which classes may extend it.
    Show answer & explanation

    Correct answer: AAn abstract class cannot be instantiated directly, but it may declare constructors, concrete methods, and instance fields that are inherited and used by its concrete subclasses.

    • A. Abstract classes exist precisely to provide shared constructors, concrete method implementations, and fields for subclasses to inherit, while being barred from direct instantiation via `new`.
    • B. Abstract classes can and often do declare constructors; those constructors run via `super()` calls from subclass constructors even though the abstract class itself can never be instantiated directly.
    • C. A class can be declared `abstract` even if every method it declares is concrete; doing so simply prevents direct instantiation, and the compiler does not require at least one abstract method.
    • D. An abstract class can be extended by another abstract class, deferring implementation of remaining abstract methods further down the hierarchy until a concrete subclass eventually provides them.
    • E. The `abstract` modifier and the `sealed` modifier are independent language features; declaring a class `abstract` has no automatic effect on whether it is sealed, non-sealed, or unrestricted.

    Subdomain 3.7: Create and use enum types with fields, methods, and constructors

    15.Given: ```java interface Discountable { double discountRate(); } public enum MembershipTier implements Discountable { BASIC(0.0), SILVER(0.05), GOLD(0.10); private final double rate; MembershipTier(double rate) { this.rate = rate; } public double discountRate() { return rate; } } ``` and a method `void applyDiscount(Discountable d)`. Which call compiles and runs correctly?

    1. A.`applyDiscount(MembershipTier.GOLD);` compiles, because `MembershipTier` implements `Discountable` and every constant is an instance of that enum type.
    2. B.`applyDiscount(MembershipTier.GOLD);` fails to compile, because enum constants cannot be widened to an interface type when passed as a method argument.
    3. C.`applyDiscount(MembershipTier.class);` compiles, because passing the enum's `Class` object satisfies any interface the enum implements.
    4. D.`applyDiscount(MembershipTier.values());` compiles, because an array of enum constants is automatically treated as a single `Discountable`.
    5. E.`applyDiscount(new Discountable());` compiles, because `Discountable` is a functional interface and can always be instantiated directly.
    Show answer & explanation

    Correct answer: A`applyDiscount(MembershipTier.GOLD);` compiles, because `MembershipTier` implements `Discountable` and every constant is an instance of that enum type.

    • A. This is correct: `MembershipTier` declares `implements Discountable`, so each constant such as `GOLD` is-a `Discountable` and can be passed anywhere that type is expected.
    • B. This is incorrect because widening a subtype reference to an implemented interface type is ordinary polymorphism in Java and applies to enum constants exactly as it does to any other object.
    • C. This is incorrect because `MembershipTier.class` is a `Class<MembershipTier>` object describing the type itself, not an instance of `Discountable`, so it does not satisfy the parameter type.
    • D. This is incorrect because `values()` returns a `MembershipTier[]` array, and an array type is never automatically convertible to a single element of an interface type.
    • E. This is incorrect because `Discountable` has no method body, and even as a functional interface it requires a lambda or concrete implementing class rather than a bare `new` expression on the interface itself.

    Domain 4: Handling Exceptions

    Subdomain 4.1: Handle exceptions using try/catch/finally, try-with-resources, and multi-catch blocks, including custom exceptions

    16.What is the output of the following program? ```java public class Test { static int compute() { try { return 1; } finally { return 2; } } public static void main(String[] args) { System.out.println(compute()); } } ```

    1. A.`2`
    2. B.`1`
    3. C.The program throws an `IllegalStateException` at runtime because two return statements conflict.
    4. D.The code fails to compile because a `finally` block cannot contain a `return` statement.
    5. E.`1` followed by `2` on separate lines, since both return statements execute.
    Show answer & explanation

    Correct answer: A`2`

    • A. When a `finally` block contains its own `return`, that return statement discards any pending return (or exception) from the try block and becomes the value the method actually returns, so `compute()` returns 2.
    • B. The `try` block's `return 1` is scheduled but not yet completed when `finally` runs; because `finally` itself returns, it overrides the pending value from `try`, so 1 is never the final result.
    • C. This is a legal, if discouraged, pattern in Java; overriding a return value from within `finally` does not raise any exception, it simply changes the returned value silently.
    • D. A `return` statement inside a `finally` block is syntactically legal in Java and compiles without error, even though most style guides discourage the pattern.
    • E. Only one value can ever be returned from a method invocation; the `finally` block's return supersedes the try block's return before it takes effect, so only 2 is produced, not both values in sequence.

    Domain 5: Working with Arrays and Collections

    Subdomain 5.1: Create arrays, List, Set, Map and Deque collections, and add, remove, update, retrieve and sort their elements

    17.Which statement correctly describes the list returned by `Arrays.asList(myIntegerArray)`, where `myIntegerArray` is an `Integer[]`?

    1. A.The list is a fixed-size view backed by the array; `set(index, value)` updates the array, while `add` or `remove` throws `UnsupportedOperationException`.
    2. B.The list is a full copy of the array's contents; calling `add` or `remove` on the list resizes the list without affecting the original array.
    3. C.The list is completely immutable, so even calling `set(index, value)` throws `UnsupportedOperationException`, just like a list created by `List.of`.
    4. D.The list lazily reads from the array on each access, so structural changes made directly to the array after creation are invisible to the returned list.
    Show answer & explanation

    Correct answer: AThe list is a fixed-size view backed by the array; `set(index, value)` updates the array, while `add` or `remove` throws `UnsupportedOperationException`.

    • A. `Arrays.asList` returns a fixed-size list backed directly by the given array. Because it shares storage with the array, `set` writes through to the array, but the list cannot grow or shrink, so `add` and `remove` throw `UnsupportedOperationException`.
    • B. The returned list is a view, not a copy; it shares the same backing storage as the array. Since it is fixed-size, `add` and `remove` are unsupported rather than triggering a resize.
    • C. Unlike `List.of`, which is fully immutable, `Arrays.asList` permits element replacement via `set`; only structural changes such as adding or removing elements are disallowed.
    • D. The list is a live view backed by the same array, so direct changes to the array elements are immediately visible through the list; nothing about the wrapping is lazy or a disconnected snapshot.

    Subdomain 5.1: Create arrays, List, Set, Map and Deque collections, and add, remove, update, retrieve and sort their elements

    18.A developer declares: ```java int[][] grid = new int[3][]; grid[0] = new int[]{1, 2}; grid[1] = new int[]{3, 4, 5}; ``` What is the value of `grid[2]` and `grid[1].length` immediately after this code runs?

    1. A.`grid[2]` is `null` and `grid[1].length` is `3`, because declaring `new int[3][]` allocates only the outer array, leaving each row unassigned until explicitly initialized.
    2. B.`grid[2]` is an empty array `int[0]` and `grid[1].length` is `3`, because Java automatically initializes unassigned rows to zero-length arrays.
    3. C.`grid[2]` is `null` and `grid[1].length` is `2`, because array lengths are fixed by the outer dimension and rows inherit the first assigned row's size.
    4. D.A `NullPointerException` is thrown when the code runs, because `new int[3][]` is not a valid way to declare a two-dimensional array in Java.
    Show answer & explanation

    Correct answer: A`grid[2]` is `null` and `grid[1].length` is `3`, because declaring `new int[3][]` allocates only the outer array, leaving each row unassigned until explicitly initialized.

    • A. `new int[3][]` creates only the outer array with three slots, each defaulting to `null` since row arrays are objects; `grid[2]` was never assigned, so it remains `null`, while `grid[1]` was explicitly assigned three elements, giving it a length of `3`.
    • B. Java does not auto-initialize unassigned rows in a jagged array to empty arrays; an unassigned row reference defaults to `null`, and accessing its length or elements without first assigning it would throw `NullPointerException`.
    • C. Jagged arrays in Java allow each row to have an independent length set individually; `grid[1]` keeps the length of the array literal explicitly assigned to it, `3`, and does not inherit a size from any other row.
    • D. Declaring `new int[3][]` is valid Java syntax for creating a jagged two-dimensional array with an unspecified inner dimension; no exception occurs simply from this declaration or from assigning individual rows afterward.

    Domain 6: Working with Streams and Lambda expressions

    Subdomain 6.2: Perform decomposition, concatenation, and reduction, and grouping and partitioning on sequential and parallel streams

    19.Which statement accurately describes the map returned by `Collectors.partitioningBy(predicate)`?

    1. A.It always contains entries for both the true and false keys, even when one of the two partitions has no matching elements.
    2. B.It contains an entry only for keys that have at least one matching element, omitting any partition that ended up empty.
    3. C.It returns a TreeMap<Boolean, List<T>> in which the false key always appears in the map after the true key.
    4. D.It throws NoSuchElementException if every element in the stream satisfies the same predicate outcome.
    Show answer & explanation

    Correct answer: AIt always contains entries for both the true and false keys, even when one of the two partitions has no matching elements.

    • A. partitioningBy is documented to always produce mappings for both possible Boolean keys; if no elements match one side of the predicate, that key still maps to an empty list rather than being absent.
    • B. Omitting an empty partition would contradict the guaranteed two-key structure of the returned map; both keys are always present regardless of how many elements land in each bucket.
    • C. The returned map type is not specified to be a TreeMap and there is no documented ordering guarantee between the two Boolean keys in the result.
    • D. No exception is thrown in this scenario; the predicate outcome simply determines whether one of the two guaranteed keys maps to an empty list instead of a populated one.

    Subdomain 6.2: Perform decomposition, concatenation, and reduction, and grouping and partitioning on sequential and parallel streams

    20.A method computes: ```java Optional<Product> mostExpensive = products.stream() .reduce(BinaryOperator.maxBy(Comparator.comparing(Product::getPrice))); ``` Which statements about this call are correct? (Select all that apply.)(Select 3)

    1. A.If products is empty, mostExpensive is Optional.empty() rather than the call throwing an exception at runtime.
    2. B.The supplied BinaryOperator must be associative for the result to be well-defined if the stream is later run in parallel.
    3. C.If comparing prices ever causes the accumulator to produce a null reduced value, a NullPointerException is thrown, since reduce disallows a null result.
    4. D.This single-argument reduce overload requires an explicit identity value, so the code shown fails to compile without one.
    5. E.Because no combiner is passed to this overload, it cannot be used safely on a stream obtained from products.parallelStream().
    6. F.The returned Optional always wraps the first tied element whenever several products share the highest price, no matter how the stream is executed.
    Show answer & explanation

    Correct answers: A, B, CIf products is empty, mostExpensive is Optional.empty() rather than the call throwing an exception at runtime.; The supplied BinaryOperator must be associative for the result to be well-defined if the stream is later run in parallel.; If comparing prices ever causes the accumulator to produce a null reduced value, a NullPointerException is thrown, since reduce disallows a null result.

    • A. The single-argument reduce overload is documented to return an empty Optional when the stream has no elements, rather than throwing, since there is nothing to seed the accumulation with.
    • B. Any BinaryOperator passed to reduce must be associative for the reduction to yield a consistent result regardless of how the runtime splits and recombines the stream during parallel execution.
    • C. reduce is specified to throw NullPointerException if the reduced value would be null, since Optional cannot hold a null element, so a null-producing accumulation surfaces as an exception rather than a silently empty result.
    • D. The overload used here is the one-argument BinaryOperator form, which intentionally has no identity parameter; an identity value is only required by the other reduce overloads, so this code compiles as written.
    • E. The single-argument reduce overload uses the same BinaryOperator as both accumulator and combiner internally, so it is fully valid on a parallel stream without requiring a separate combiner argument.
    • F. When multiple elements tie under the comparator, which one is ultimately retained is not guaranteed to be the first encountered, especially under parallel execution where partial results are combined in an unspecified order.

    Subdomain 6.1: Use Java object and primitive Streams, including lambda expressions implementing functional interfaces, to create, filter, transform, process, and sort data

    21.```java Predicate<String> isEmpty = String::isEmpty; Predicate<String> isShort = s -> s.length() < 5; ``` Select all statements that are true about combining these predicates using `Predicate` default methods.(Select 3)

    1. A.`isEmpty.and(isShort)` evaluates `isEmpty` first and only evaluates `isShort` when `isEmpty` returns `true`, short-circuiting otherwise.
    2. B.`isEmpty.or(isShort)` evaluates `isShort` only when `isEmpty` returns `false`, short-circuiting otherwise, like the logical `||` operator.
    3. C.`isEmpty.negate()` returns a new predicate that tests `true` for exactly the strings that `isEmpty` tests `false` for.
    4. D.`isEmpty.and(isShort)` evaluates both predicates unconditionally every time, regardless of the result of `isEmpty`.
    5. E.Calling `isEmpty.negate()` mutates the original `isEmpty` predicate, so subsequent calls to `isEmpty.test(...)` return the negated result.
    6. F.`and`, `or`, and `negate` are abstract methods that every implementation of `Predicate` must override individually.
    7. G.`isEmpty.and(isShort)` produces a `BiPredicate<String, String>`, because combining two predicates requires two input parameters.
    Show answer & explanation

    Correct answers: A, B, C`isEmpty.and(isShort)` evaluates `isEmpty` first and only evaluates `isShort` when `isEmpty` returns `true`, short-circuiting otherwise.; `isEmpty.or(isShort)` evaluates `isShort` only when `isEmpty` returns `false`, short-circuiting otherwise, like the logical `||` operator.; `isEmpty.negate()` returns a new predicate that tests `true` for exactly the strings that `isEmpty` tests `false` for.

    • A. `Predicate.and` is specified to behave like the logical `&&` operator: it short-circuits, so the second predicate is only invoked when the first one returns `true`.
    • B. `Predicate.or` mirrors the logical `||` operator: the second predicate is only invoked when the first one returns `false`, avoiding unnecessary evaluation once a `true` result is already known.
    • C. `negate()` returns a predicate whose result is the logical complement of the original for every input, so it is `true` exactly where the original predicate would have returned `false`.
    • D. `and` short-circuits rather than evaluating unconditionally; if the first predicate already returns `false`, the second predicate is skipped entirely.
    • E. `Predicate` methods like `negate` are functional and return a brand-new `Predicate` instance rather than modifying the receiver, so the original `isEmpty` reference continues to behave exactly as before.
    • F. `and`, `or`, and `negate` are default methods provided by the `Predicate` interface itself; implementers only need to supply the single abstract `test` method, not these combinators.
    • G. `Predicate.and` returns another `Predicate<T>` operating on the same single input type, not a `BiPredicate`; both predicates are still applied to the same one argument.

    Domain 7: Packaging and Deploying Java Code

    Subdomain 7.1: Define modules and expose module content, including that by reflection, and declare module dependencies, define services, providers, and consumers

    22.A class is compiled without a `module-info.java` and placed on the classpath at runtime alongside a fully modularized application. Which statements correctly describe the unnamed module it belongs to? (Select 3)(Select 3)

    1. A.It can read every other module on the module path as well as every other class on the classpath, without needing explicit `requires` directives.
    2. B.It exposes all of its packages to every named module that requires it, since the unnamed module exports everything it contains.
    3. C.Named modules cannot declare a plain `requires` on the unnamed module, because the unnamed module has no fixed, referenceable name.
    4. D.It gains qualified access to a named module's internals whenever that module's `opens ... to` clause lists a wildcard for unnamed modules.
    5. E.It is compiled with strong encapsulation enabled by default, so accessing package-private members across the classpath still fails.
    6. F.It cannot itself declare `exports`, `opens`, `requires`, or other module directives, since it has no module descriptor at all.
    Show answer & explanation

    Correct answers: A, C, FIt can read every other module on the module path as well as every other class on the classpath, without needing explicit `requires` directives.; Named modules cannot declare a plain `requires` on the unnamed module, because the unnamed module has no fixed, referenceable name.; It cannot itself declare `exports`, `opens`, `requires`, or other module directives, since it has no module descriptor at all.

    • A. The unnamed module exists to preserve classpath-style behavior; it automatically reads every module on the module path and sees every classpath class, mirroring pre-module-system access.
    • B. Named modules do not automatically read the unnamed module, so exposing all packages from the unnamed module's side has no effect; named modules cannot see into it unless they resort to classpath tricks outside the module system.
    • C. The unnamed module lacks a stable, declarable name, so a named module's `module-info.java` has no syntax for expressing a `requires` on it directly.
    • D. There is no wildcard syntax for targeting unnamed-module callers inside a module declaration's `opens ... to` clause; that kind of access is granted only through command-line options, not source-level directives.
    • E. Classpath code is not subject to the module system's strong encapsulation; classic classpath-era reflective and same-package access rules continue to apply to the unnamed module.
    • F. Because it has no `module-info.java`, the unnamed module cannot express any module directive; its access characteristics come entirely from being treated specially by the module system, not from any descriptor.

    Subdomain 7.2: Compile Java code, create modular and non-modular jars, runtime images, and implement migration to modules using unnamed and automatic modules

    23.Which statements accurately describe the unnamed module in the Java Platform Module System? (Select all that apply)(Select 3)

    1. A.Every class loaded from the classpath (not the module path) belongs to the unnamed module.
    2. B.The unnamed module reads every other module on the module path, including all named and automatic modules.
    3. C.The unnamed module exports all of its packages, making them accessible to any module that reads it.
    4. D.Named modules can read the unnamed module by default without any extra configuration.
    5. E.The unnamed module has an explicit, addressable name that can be referenced in a `requires` clause.
    6. F.There is exactly one unnamed module for the entire JVM, shared across every class loader.
    7. G.The unnamed module can never be granted read access to a specific named module, even with command-line flags.
    8. H.Types in the unnamed module can be referenced from a `module-info.java` via a `requires` directive, similar to naming a regular module.
    Show answer & explanation

    Correct answers: A, B, CEvery class loaded from the classpath (not the module path) belongs to the unnamed module.; The unnamed module reads every other module on the module path, including all named and automatic modules.; The unnamed module exports all of its packages, making them accessible to any module that reads it.

    • A. Classes on the classpath are not attributed to any named module, so the JVM groups them into the unnamed module.
    • B. The unnamed module implicitly reads the entire module graph, both explicit and automatic modules, so classpath code can still see application and platform APIs.
    • C. The unnamed module exports every one of its packages unconditionally, mirroring the permissive behavior classpath code had before the module system existed.
    • D. By default, named modules do not read the unnamed module; a named module must opt in with a mechanism like `--add-reads` naming `ALL-UNNAMED` to see classpath classes.
    • E. The unnamed module has no name at all, which is precisely why it cannot appear on the right-hand side of a `requires` clause in any module descriptor.
    • F. Each class loader gets its own unnamed module rather than the JVM sharing a single one, so a JVM using multiple class loaders can have multiple unnamed modules simultaneously.
    • G. `--add-reads ALL-UNNAMED=<module>` on the command line is exactly the mechanism used to grant the unnamed module readability of a specific named module, so this blanket denial is incorrect.
    • H. Because the unnamed module has no name, it cannot be the target of a `requires` directive in any `module-info.java`; only automatic and explicit modules can be required by name.

    Subdomain 7.2: Compile Java code, create modular and non-modular jars, runtime images, and implement migration to modules using unnamed and automatic modules

    24.A team is planning how to modularize a monolithic legacy application with a deep dependency tree of internal libraries. Which statements about choosing between top-down and bottom-up migration strategies are accurate? (Select all that apply)(Select 3)

    1. A.In a bottom-up approach, a library deep in the dependency tree can be fully modularized only after every library it depends on has already been modularized or is otherwise safe to require directly.
    2. B.In a top-down approach, the top-level application module can be created first while its unconverted dependencies are added to the module path as automatic modules.
    3. C.A bottom-up migration typically produces a shorter list of automatic modules remaining on the module path at any given point, since dependencies are converted before their consumers.
    4. D.A top-down migration guarantees that no automatic modules will ever appear on the module path, because the application module's `requires` clauses force immediate conversion of every dependency.
    5. E.Automatic modules can serve as a temporary bridge in a top-down migration, but bottom-up migration is not permitted to use automatic modules at any point.
    6. F.Bottom-up migration tends to defer the point at which the top-level application itself gains a `module-info.java`, since it is the last piece converted.
    Show answer & explanation

    Correct answers: A, B, CIn a bottom-up approach, a library deep in the dependency tree can be fully modularized only after every library it depends on has already been modularized or is otherwise safe to require directly.; In a top-down approach, the top-level application module can be created first while its unconverted dependencies are added to the module path as automatic modules.; A bottom-up migration typically produces a shorter list of automatic modules remaining on the module path at any given point, since dependencies are converted before their consumers.

    • A. Bottom-up migration works from the leaves inward, so a library can only become a clean named module once its own dependencies are already resolvable as real modules rather than requiring workarounds.
    • B. Top-down migration modularizes the application first and lets its still-unconverted dependencies sit on the module path as automatic modules until they too are converted, which is the defining trade-off of this approach.
    • C. Because bottom-up migration converts dependencies before the modules that consume them, at any point in the process fewer of the remaining unconverted pieces need to be bridged in as automatic modules.
    • D. Top-down migration explicitly relies on automatic modules as a bridge for dependencies that are not yet modularized; it does not force every dependency to convert immediately, so this guarantee is false.
    • E. Both strategies can use automatic modules as a temporary bridge for whichever pieces are not yet converted; bottom-up migration is not restricted from using them either, so this restriction is false.
    • F. Since bottom-up migration works inward from the leaves, the top-level application is naturally the last component converted, so it keeps running as the unnamed module the longest.

    Domain 8: Managing Concurrent Code Execution

    Subdomain 8.1: Create both platform and virtual threads

    25.Consider the following code: ```java ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(() -> { Thread.sleep(5000); return "done"; }); boolean cancelled = future.cancel(true); ``` Assume `cancel(true)` executes while the task is still inside `Thread.sleep(5000)`. Select the statements that correctly describe the resulting state. (Select 3)(Select 3)

    1. A.`cancelled` is `false` because `cancel(true)` only takes effect on tasks that have not yet started running.
    2. B.`future.isCancelled()` now returns `true`, reflecting that the task was cancelled before it completed normally.
    3. C.The worker thread running the task is interrupted, which typically makes the blocking `Thread.sleep` call throw.
    4. D.`future.isDone()` returns `false` because cancellation is not treated as a terminal state for the task.
    5. E.Calling `future.get()` after this call returns `null` rather than throwing any exception at all.
    6. F.`future.get()` after this call throws a `CancellationException` rather than returning a result.
    7. G.The executor automatically resubmits the cancelled task to a brand-new idle worker thread for another attempt.
    Show answer & explanation

    Correct answers: B, C, F`future.isCancelled()` now returns `true`, reflecting that the task was cancelled before it completed normally.; The worker thread running the task is interrupted, which typically makes the blocking `Thread.sleep` call throw.; `future.get()` after this call throws a `CancellationException` rather than returning a result.

    • A. Passing `true` to `cancel` specifically allows cancellation of a task that has already started, not just one still waiting in a queue. Since the task was running, `cancel(true)` returns `true` here, not `false`.
    • B. Once cancellation succeeds, `isCancelled()` reports `true` for that `Future` from then on. This reflects that the task was stopped rather than allowed to finish and produce its normal result.
    • C. `cancel(true)` interrupts the worker thread executing the task if it is running, and `Thread.sleep` responds to interruption by throwing `InterruptedException`. This is the standard mechanism by which a running blocking call is unwound during cancellation.
    • D. Cancellation is itself a terminal outcome for a `Future`; once cancelled, `isDone()` returns `true` just as it would for normal completion or an execution failure. It does not remain `false` after a successful cancellation.
    • E. A cancelled task's `Future` does not silently return `null`; retrieving its result after cancellation throws an exception instead of yielding a placeholder value. Treating cancellation as equivalent to a `null` result would hide that the task never completed.
    • F. After a `Future` has been cancelled, calling `get()` throws `CancellationException` rather than returning any value, since the underlying task's result was never produced. This is the documented behavior for retrieving results from a cancelled `Future`.
    • G. `ExecutorService` has no built-in retry mechanism; a cancelled task is simply abandoned and never automatically resubmitted. Any retry logic would have to be implemented explicitly by the calling code.

    Subdomain 8.3: Process Java collections concurrently and utilize parallel streams

    26.A pipeline processes `orders.parallelStream()` and needs to return the first order, by natural encounter order, whose total exceeds a threshold, purely for correctness rather than raw speed. Which terminal operation should be used, and why?

    1. A.`findFirst()`, because it always returns the element that is first in the stream's encounter order even when the pipeline runs across multiple threads.
    2. B.`findAny()`, because in a parallel pipeline it is optimized to return the first-encountered element while avoiding the synchronization cost of `findFirst()`.
    3. C.`findFirst()`, because encounter order is only meaningful for sequential streams, so calling it on a parallel stream silently falls back to sequential execution.
    4. D.`findAny()`, because for parallel streams the JDK guarantees encounter-order results identical to `findFirst()` while running noticeably faster.
    Show answer & explanation

    Correct answer: A`findFirst()`, because it always returns the element that is first in the stream's encounter order even when the pipeline runs across multiple threads.

    • A. Correct: `findFirst()` is specified to honor the stream's encounter order regardless of whether the pipeline runs sequentially or in parallel, which is required here since the order-first element must be returned deterministically.
    • B. This is incorrect: `findAny()` is intentionally unconstrained by encounter order for better performance, so it may return any matching element rather than specifically the first one in source order.
    • C. This is incorrect: `findFirst()` does not force a fallback to sequential execution; it still runs across the parallel pipeline's threads but coordinates results to honor encounter order.
    • D. This is incorrect: `findAny()` explicitly does not guarantee encounter order, trading that guarantee for potential speed, so it cannot be relied on to match `findFirst()` results.

    Subdomain 8.2: Develop thread-safe code, using locking mechanisms and concurrent API

    27.A caching layer uses `ReentrantReadWriteLock` to protect a `Map`. A thread currently holds the read lock and, inside that same critical section, attempts to acquire the write lock on the same `ReentrantReadWriteLock` instance in order to refresh a stale entry before releasing the read lock. What happens?

    1. A.The write lock acquisition blocks indefinitely (or times out with `tryLock`) because upgrading from a held read lock to the write lock is not supported
    2. B.The write lock is granted immediately because `ReentrantReadWriteLock` automatically upgrades a held read lock into a full write lock for that same owning thread
    3. C.The call throws `IllegalMonitorStateException` immediately because a thread can never hold both a read lock and attempt a write lock
    4. D.The write lock is granted immediately, but every other reader thread's read lock is silently revoked in order to preserve exclusivity
    Show answer & explanation

    Correct answer: AThe write lock acquisition blocks indefinitely (or times out with `tryLock`) because upgrading from a held read lock to the write lock is not supported

    • A. `ReentrantReadWriteLock` does not support upgrading a held read lock to a write lock; attempting it while other readers might hold the read lock (including this thread) causes the write lock acquisition to block or time out, so the thread must release the read lock first.
    • B. There is no automatic upgrade path from read to write lock in `ReentrantReadWriteLock`; the documented pattern for this class explicitly states downgrading write-to-read is possible but upgrading read-to-write is not.
    • C. No exception is thrown for this sequence; the acquisition simply blocks (or times out with a timed `tryLock`) rather than failing fast with a monitor-state exception.
    • D. The lock implementation has no mechanism to forcibly revoke another thread's held read lock; write lock acquisition instead waits for all outstanding read locks to be released normally.

    Domain 9: Using Java I/O API

    Subdomain 9.1: Read and write console and file data using I/O streams

    28.A method reads lines from a text file using `BufferedReader.readLine()` in a `while` loop. Which condition correctly signals that the end of the stream has been reached?

    1. A.`readLine()` returns `null`.
    2. B.`readLine()` throws an `EOFException`.
    3. C.`readLine()` returns an empty string `""`.
    4. D.`readLine()` returns the integer value `-1`.
    Show answer & explanation

    Correct answer: A`readLine()` returns `null`.

    • A. BufferedReader.readLine() is documented to return null when the end of the stream is reached, which is the standard sentinel used to terminate reading loops.
    • B. readLine() does not throw EOFException on reaching the end of the stream; that exception is associated with DataInputStream methods like readFully or readUTF, not BufferedReader.
    • C. An empty string is a valid return value representing a blank line within the file content, not a signal of end-of-stream, so it cannot be used to detect EOF.
    • D. The integer -1 sentinel is used by byte- and character-level read methods such as InputStream.read() or Reader.read(), not by the line-based readLine() method, which returns a String or null.

    Subdomain 9.1: Read and write console and file data using I/O streams

    29.A developer needs to write primitive values such as `int` and `double` to a file in a compact binary format that can later be read back with matching typed read methods. Which pair of classes should be used together?

    1. A.`DataOutputStream` wrapping a `FileOutputStream` for writing, and `DataInputStream` wrapping a `FileInputStream` for reading.
    2. B.`PrintWriter` wrapping a `FileWriter` for writing, and `BufferedReader` wrapping a `FileReader` for reading.
    3. C.`ObjectOutputStream` wrapping a `FileWriter` for writing, and `ObjectInputStream` wrapping a `FileReader` for reading.
    4. D.`FileWriter` alone for writing primitives directly, and `FileReader` alone for reading them back as typed values.
    Show answer & explanation

    Correct answer: A`DataOutputStream` wrapping a `FileOutputStream` for writing, and `DataInputStream` wrapping a `FileInputStream` for reading.

    • A. DataOutputStream provides typed methods like writeInt and writeDouble that encode primitives in a compact binary format, and DataInputStream provides the matching readInt and readDouble methods to decode them, which is the correct pairing.
    • B. PrintWriter and BufferedReader operate on text representations of values via print/println and readLine, requiring manual parsing back to primitives rather than a compact binary format with typed reads.
    • C. ObjectOutputStream and ObjectInputStream require byte streams, not character Writers or Readers, as their constructor arguments, so this pairing does not compile as described.
    • D. FileWriter only exposes character-based write methods for text and has no typed methods for writing primitives like int or double in binary form.

    Subdomain 9.2: Serialize and de-serialize Java objects

    30.A class `Session` implements `Serializable` and has a field `private transient String authToken;` that stores a live authentication token. After serializing a `Session` instance to a file and later deserializing it in a new JVM run, what value does `authToken` hold in the reconstructed object?

    1. A.The field holds `null`, because a transient field is excluded from the serialized stream and is left at its default value on deserialization.
    2. B.The field holds the original value, because the JVM caches transient fields separately in a class-level table and restores them automatically.
    3. C.Serialization throws `NotSerializableException`, because transient fields are not permitted on a class that implements `Serializable`.
    4. D.The field holds an empty string, because `ObjectOutputStream` substitutes an empty string for any field marked `transient` before writing it.
    5. E.The field holds the value from the last `Session` serialized in the same JVM, because transient fields share a single static slot across instances.
    Show answer & explanation

    Correct answer: AThe field holds `null`, because a transient field is excluded from the serialized stream and is left at its default value on deserialization.

    • A. The `transient` modifier tells `ObjectOutputStream` to skip writing that field's value, so nothing about the token is present in the stream. On deserialization the field is simply left at its type's default value, which is `null` for a `String`.
    • B. No such class-level cache exists for transient fields; the JVM does not retain or restore their runtime values across serialization boundaries. Once excluded from the stream, the value is gone unless custom code writes it separately.
    • C. Marking a field `transient` is fully legal on a `Serializable` class and is the standard mechanism for excluding sensitive or non-serializable state. No exception is thrown because of this modifier alone.
    • D. `ObjectOutputStream` does not substitute any placeholder text for transient fields; it simply omits them from the stream entirely. The field keeps its type's default value after reconstruction, not an empty string.
    • E. Transient fields are ordinary instance fields for all purposes except the serialization mechanism, so each `Session` object keeps its own independent field slot. There is no shared static storage implied by the `transient` keyword.

    Subdomain 9.3: Construct, traverse, create, read, and write Path objects and their properties using the java.nio.file API

    31.A configuration loader contains: ```java Path base = Path.of("/opt/app/config"); Path other = Path.of("/etc/settings.conf"); Path result = base.resolve(other); System.out.println(result); ``` What is printed?

    1. A.It prints "/etc/settings.conf", because resolving an absolute path against any base simply returns that absolute path unchanged
    2. B.It prints "/opt/app/config/etc/settings.conf", because resolve always appends the second path's elements onto the base path
    3. C.It prints "/opt/app/config/settings.conf", because resolve keeps only the base directory and the final file name of the second path
    4. D.It throws an exception, because resolve requires the second argument to be relative when the base path is already absolute
    Show answer & explanation

    Correct answer: AIt prints "/etc/settings.conf", because resolving an absolute path against any base simply returns that absolute path unchanged

    • It prints "/etc/settings.conf", because resolving an absolute path against any base simply returns that absolute path unchanged. When the argument passed to resolve is already absolute, resolve returns that argument unchanged and discards the base path entirely, which matches this output.
    • It prints "/opt/app/config/etc/settings.conf", because resolve always appends the second path's elements onto the base path. This would be the outcome only if the second path were relative; because it is absolute, resolve does not append it onto the base path this way.
    • It prints "/opt/app/config/settings.conf", because resolve keeps only the base directory and the final file name of the second path. This assumes only the file name from the second path is appended to the base, but resolve never extracts a trailing element like that from an absolute argument.
    • It throws an exception, because resolve requires the second argument to be relative when the base path is already absolute. resolve does not validate or reject absolute arguments; it simply short-circuits and returns the absolute argument, so no exception occurs here.

    Domain 10: Implementing Localization

    Subdomain 10.1: Implement localization using locales and resource bundles

    32.A developer writes `new MessageFormat("It''s {0} percent, not '{0}'").format(new Object[]{50})`. Which statements about the output and quoting rules are correct? Select all that apply.(Select 3)

    1. A.The doubled single quotes (`''`) in `"It''s"` produce a literal apostrophe in the output, rendering `"It's"`.
    2. B.The braces wrapped in single quotes, `'{0}'`, are treated as literal text and are not substituted with the argument.
    3. C.The final formatted output is `"It's 50 percent, not {0}"`.
    4. D.`MessageFormat` throws `IllegalArgumentException` because the pattern mixes quoted and unquoted braces.
    5. E.The doubled single quotes are collapsed to nothing rather than producing a quote character, yielding `"Its 50 percent, not {0}"`.
    6. F.Because one pair of braces is quoted, `MessageFormat` disables substitution for every `{0}` in the pattern, printing the index literally throughout.
    Show answer & explanation

    Correct answers: A, B, CThe doubled single quotes (`''`) in `"It''s"` produce a literal apostrophe in the output, rendering `"It's"`.; The braces wrapped in single quotes, `'{0}'`, are treated as literal text and are not substituted with the argument.; The final formatted output is `"It's 50 percent, not {0}"`.

    • A. In `MessageFormat` pattern syntax, two consecutive single quotes are the escape sequence for a literal single quote character, so `"It''s"` renders as `"It's"` in the output.
    • B. Text enclosed in a matching pair of single quotes is treated as a literal string rather than being interpreted as a placeholder, so `'{0}'` is emitted as the literal characters `{0}` instead of being substituted.
    • C. Combining the doubled-quote escape for the apostrophe with the quoted literal braces, the unquoted `{0}` is substituted with `50` while the quoted `{0}` stays literal, producing exactly this combined string.
    • D. Mixing quoted and unquoted brace occurrences in the same pattern is valid syntax; `MessageFormat` processes each independently rather than rejecting the pattern with an exception.
    • E. Doubled single quotes are the documented escape for producing one literal quote character, not for producing no character at all, so the apostrophe is retained in the output.
    • F. Quoting is scoped to the specific text between a pair of quote marks; it does not globally disable substitution for other occurrences of the same argument index elsewhere in the pattern.

    Domain 11: Candidates are also expected to

    Subdomain 11.1: Understand the basics of Java Logging API

    33.Which statements about Logger's convenience methods and the log method are correct? (Select all that apply.)(Select 3)

    1. A.Calling logger.fine("message") is functionally equivalent to calling logger.log(Level.FINE, "message") directly
    2. B.Passing null as the message argument to logger.info(null) throws a NullPointerException immediately at call time
    3. C.logger.log(Level.WARNING, "failed", exception) records the supplied Throwable alongside the message for output
    4. D.Convenience methods like logger.warning(String) have a Supplier<String> overload so the message is computed lazily only if enabled
    5. E.logger.severe(msg) bypasses the logger's configured level entirely, always publishing regardless of any filtering
    6. F.Calling logger.config(msg) logs at Level.CONFIG, considered more severe than Level.WARNING for filtering purposes
    7. G.logger.log(Level.OFF, "message") publishes using the lowest possible severity value available in the framework
    Show answer & explanation

    Correct answers: A, C, DCalling logger.fine("message") is functionally equivalent to calling logger.log(Level.FINE, "message") directly; logger.log(Level.WARNING, "failed", exception) records the supplied Throwable alongside the message for output; Convenience methods like logger.warning(String) have a Supplier<String> overload so the message is computed lazily only if enabled

    • A. The named convenience methods such as fine are documented as shorthand that simply calls the general log method with the corresponding named level, so the two calls behave identically.
    • B. The logging API's convenience methods are documented to tolerate null for most arguments, including the message, rather than throwing on a null message parameter.
    • C. The overload accepting a Throwable is specifically documented to associate that exception with the LogRecord so handlers and formatters can include stack trace information in the output.
    • D. Logger provides Supplier-based overloads on its convenience methods precisely so that expensive message construction can be deferred and skipped entirely when the level check would suppress the record anyway.
    • E. The severe method still goes through the same level-filtering logic as every other convenience method; it is not exempt from being suppressed if a logger's configured level were somehow set above SEVERE.
    • F. CONFIG's documented integer value (700) is lower than WARNING's (900), meaning CONFIG is actually less severe, not more, contradicting the claim made here.
    • G. OFF represents the highest possible integer value in the Level hierarchy, intended to suppress logging entirely, not the lowest; describing it as the lowest severity misstates its purpose and value.

    Subdomain 11.2: Use Annotations such as Override, FunctionalInterface, Deprecated, SuppressWarnings, and SafeVarargs

    34.A code reviewer sees the following and is deciding whether `@SuppressWarnings` is being used appropriately: ``` @SuppressWarnings({"unchecked", "rawtypes"}) List list = new ArrayList(); List<String> strings = (List<String>) list; ``` Which statement best evaluates this usage?

    1. A.The usage is reasonable: `"rawtypes"` covers the raw `list` declaration, and `"unchecked"` covers the cast to `List<String>`, addressing two distinct warnings.
    2. B.The usage is redundant: a single `"unchecked"` value already suppresses the raw type warning too, so listing `"rawtypes"` separately adds nothing further.
    3. C.The usage is incorrect: `@SuppressWarnings` requires a single string value, never an array of strings, so this exact snippet fails to compile as written.
    4. D.The usage is ineffective: `@SuppressWarnings` can only target methods and types, so placing it above a local variable declaration achieves nothing.
    Show answer & explanation

    Correct answer: AThe usage is reasonable: `"rawtypes"` covers the raw `list` declaration, and `"unchecked"` covers the cast to `List<String>`, addressing two distinct warnings.

    • A. `"rawtypes"` and `"unchecked"` are distinct, separately recognized warning categories in javac; using a raw `List` type triggers the rawtypes warning, and casting to a parameterized type triggers the unchecked warning, so both keys are needed to cover both diagnostics.
    • B. Raw type usage and unchecked casts are tracked as separate warning kinds by the compiler; suppressing `"unchecked"` alone does not also suppress `"rawtypes"` warnings, so both values genuinely serve a purpose here rather than one being redundant.
    • C. `@SuppressWarnings`'s `value` element is declared as `String[]`, and Java's array-initializer shorthand allows curly-brace syntax for array-valued annotation elements, so supplying multiple strings in braces compiles correctly.
    • D. `@SuppressWarnings`'s `@Target` includes `LOCAL_VARIABLE` among other element kinds, so annotating a local variable declaration is valid and does suppress warnings that would otherwise be reported for the initialization on that line.

    Subdomain 11.3: Use generics, including wildcards

    35.A developer calls a generic method without assigning the result to a variable: ```java process(Collections.emptyList()); // compile error: cannot infer type ``` Given `process` is declared as `void process(List<String> list)`, which fix resolves the compile error without changing `process`'s signature?

    1. A.Provide an explicit type witness, `process(Collections.<String>emptyList())`, telling the compiler which type argument to use for `emptyList()`.
    2. B.Replace `Collections.emptyList()` with `new ArrayList<>()`, because diamond inference always resolves generic method calls regardless of the surrounding context.
    3. C.Add an explicit cast, `process((List<String>) Collections.emptyList())`, because casting a raw `List` always restores full generic type safety.
    4. D.Change `emptyList()` to `emptyList(String.class)`, because passing the class object lets the compiler infer the generic type without a witness.
    Show answer & explanation

    Correct answer: AProvide an explicit type witness, `process(Collections.<String>emptyList())`, telling the compiler which type argument to use for `emptyList()`.

    • A. This is correct: an explicit type witness supplies the type argument directly to the generic method call, letting the compiler resolve `Collections.<String>emptyList()` to `List<String>` and match the expected parameter type.
    • B. Diamond inference relies on target-type context such as a variable declaration or assignment; when a generic method call is passed directly as an argument without such context, the diamond operator would face the same inference difficulty here.
    • C. `Collections.emptyList()` already returns a properly parameterized `List<Object>`-compatible reference in this context, not a raw type, so an explicit cast is unnecessary and does not address the underlying type-inference failure.
    • D. `Collections.emptyList()` does not have an overload that accepts a `Class` object, so this call would not compile at all, rather than resolving the type-inference ambiguity.

    Want the full experience?

    These are just samples. Practice the full Oracle Java SE 21 Developer Professional question bank in quiz mode — free, no signup, with domain practice and exam simulation.