These tests accompany the chapter drafts. They run with JDK 25 without preview, on copies of sources: deliberately incorrect variants must not remain in positive programs. Every activity specifies an expected answer, so the reader can compare reasoning with observed behavior. Reader testing and gates EV0–EV5 remain open.
C13-A01 – Two Implementations, One Reference
Task. In DemoInterfaces.java, assign a Temperature to a Measurable reference and try calling first value(), then description(). Explain which call compiles and which does not, although both refer to the same object.
Criterion and solution. value() compiles because it is in the Measurable contract; description() is not visible from the reference's declared type. The object remains a Temperature, but the compiler uses the reference type to establish available operations. A new Describable variable can refer to the same object and call description().
C13-P01 – Default Conflict
Task. Before compiling DemoDefaultConflict.java, predict the printed line. In a copy remove the override of name() from Choice and compile.
Criterion and solution. The correct version prints first+second. Without the override, the class would receive two incompatible default methods and the compiler rejects the declaration; implements order does not resolve the conflict.
C13-D01 – A New Outcome
Task. Add Suspended(String reason) to the implementations permitted by the sealed interface of DemoOutcome.java. Compile before changing the switch, then add the missing branch.
Criterion and solution. After the type is added, the switch no longer covers all permitted outcomes and does not compile. A branch case Suspended suspended -> ... restores exhaustiveness. The reader can explain why a default would hide the need to review the new outcome's meaning.
C14-A01 – How Long Does an Annotation Exist?
Task. Run DemoAnnotations.java with Label.java. In a copy change retention from RUNTIME to CLASS, recompile and rerun.
Criterion and solution. The initial version prints catalog and teaching; the second prints no labels because ordinary reflection does not see them at runtime. Compilation remains valid: retention controls subsequent availability of metadata, rather than the meaning of the two strings.
C14-G01 – Recognizing a Processor
Task. Compile the three C14 sources, then explicitly invoke LabelProcessor with -processor LabelProcessor -proc:only. Indicate whether the compiler note appears before or after starting main.
Criterion and solution. The note label present on DemoAnnotations appears during javac; main is not started by -proc:only. A processor works on the program model at compile time, while getAnnotationsByType is a runtime read.
C14-P01 – A Declared Check
Task. Design @Responsible for a method: choose @Target, @Retention and an element String value(). Describe which component will read the annotation, without claiming that Java automatically sends a notification to the responsible person.
Criterion and solution. ElementType.METHOD limits placement. RUNTIME is justified if an application reads it through reflection; SOURCE or CLASS may suffice for a compile-time check. The value is metadata and requires separate code to produce effects.
C14-D01 – Inheritance and Repeatable Annotations
Task. Predict the four lines of DemoPolicies.java, then the two labels of DemoReminders.java. Explain why getDeclaredAnnotationsByType and getAnnotationsByType answer different questions about the subclass and why two reminders do not activate a scheduler on their own.
Criterion and solution. The base annotation can be visible on the derived class thanks to @Inherited, but does not become a declaration written on the derived class. Both repeated annotations remain two readable values in declared order; using them as execution times requires a separate application component.
C15-A01 – Why Does the Cast Disappear?
Task. In GenericsDemo.java, identify where the compiler knows the type returned by titles.pop(). Then try passing 3 to titles.push in a copy of the file.
Criterion and solution. Stack<String> fixes T to String in method signatures used by the caller. Inserting the integer does not compile; there is no need to wait for extraction to discover incompatibility. The explanation does not attribute checking to a hand-written cast.
C15-P01 – Reading and Writing with Wildcards
Task. Modify copyNumbers to read from List<? extends Integer> into an Integer variable and receive List<? super Integer> as destination. Try List<Number> and List<Object>; then attempt to directly read an Integer from the destination.
Criterion and solution. Both lists can receive an Integer, but the type guaranteed for reading from the super parameter is only Object. Wildcard direction follows the operation the method must perform.
C15-D01 – A Tempting Assignment
Task. Add List<Number> numbers = List.of(1, 2); and, on a separate line, try assigning a List<Integer> variable to List<Number>. Distinguish the two cases.
Criterion and solution. The first can compile because the compiler constructs a list in the context of the required type. The second does not compile: an already typed List<Integer> does not become a List<Number>, otherwise a Double could be inserted into it.
C15-G01 – The Bridge After Erasure
Task. Compile BridgeDemo.java and inspect TitleStore with javap -p. Identify the method with parameter String and the one with parameter Object. Explain which dispatch problem the latter solves, without claiming that source code declared two deliberate overloads.
Criterion and solution. After erasure the inherited signature uses Object; the compiler adds a bridge method adapting the call to the specialized String method. The generic relationship remains checked by the compiler at the point of use.
C16-A01 – Reading Composition
Task. Before running FunctionsDemo.java, follow " Java " through strip, toUpperCase, the predicate and printing. Repeat for " Go ".
Criterion and solution. The first text becomes JAVA and produces JAVA: 4; the second becomes GO but does not exceed the minimum length of 3. The answer distinguishes transformation, decision and printing effect.
C16-P01 – Capturing a Local Value
Task. Move the length check into Predicate<String> longEnough = text -> text.length() >= minimumLength;. Then try incrementing minimumLength after the declaration.
Criterion and solution. The lambda works as long as the local variable is effectively final. After incrementing, the compiler rejects capture. Removing final from the declaration does not change this rule.
C16-D01 – Recursion with a Stop
Task. Draw the calls of factorial(3) and predict the result. Then try factorial(-1) in a copy and explain why the initial check is necessary.
Criterion and solution. Calls reach factorial(0), returning 1; climbing back up we obtain 1, 2 and 6. A negative value throws IllegalArgumentException, avoiding descent without a suitable stopping case.
C16-G01 – The Same Operation in Three Forms
Task. In LambdaPathDemo.java, follow values 10 and 3 in the anonymous, lambda and method-reference implementations. Change add(2) to add(5) and predict the last line. Then run CaptureDemo.java and explain why its two lines differ.
Criterion and solution. The first two implementations subtract and print 7, the reference to sum produces 13; add(5) produces 18. In CaptureDemo, the local value 3 remains stable while field total changes between calls, producing 3 and 6. The reader distinguishes captured value and mutable object state.
C17-A01 – Duplicates and Order
Task. Predict the first three lines of CollectionsDemo.java. Indicate which contract preserves the second Java and which eliminates it. Then transfer the choice to a new case: the library must store two successive loans of the same book and, separately, codes of books already shown in the showcase. Choose both collection types and explain why one alone cannot be used without losing a required property.
Criterion and solution. The lines are [Java, Nets, Java], [Java, Nets], [Nets, Java]. List preserves duplicates and positions; LinkedHashSet preserves uniqueness and encounter order; reversed() offers the opposite view. Both loans are distinct events and remain in a List<Loan>, even if they concern the same book. Codes already displayed instead form a Set<String>; LinkedHashSet is useful if first-display order matters. The answer must associate each choice with its requirement, rather than just name a class.
C17-P01 – The Library's Stack
Task. In a copy of the program, add a third value to the Deque and predict the order of three pop() calls. Explain how this use connects to the stack constructed in earlier chapters. Now change the problem: requests must leave in arrival order. Which contract would you use and which operations would you replace?
Criterion and solution. Values leave in the reverse of push insertion order. The interface is generic and implementation ArrayDeque replaces the teaching stack for ordinary use, without changing the LIFO principle. For the new FIFO request, use the Queue or Deque contract, inserting at the tail with offer and retrieving from the head with poll or remove according to the chosen empty-queue policy. The concrete structure can remain ArrayDeque; the meaning of operations changes.
C17-D01 – The Comparator That Loses a Title
Task. Remove thenComparing(Comparator.naturalOrder()) from the program's TreeSet and run it. Explain why one four-letter title is missing. Then propose a criterion sorting by length first and, at equal lengths, retaining different titles; also indicate a case where directly choosing HashSet and sorting only presentation would be simpler.
Criterion and solution. Java and Nets have the same length; a comparator looking only at length returns zero and the set treats them as equivalent. A second alphabetical comparison distinguishes both titles. If the requirement is only avoiding duplicates and order is needed in an occasional print, a HashSet can be retained and a copy sorted at presentation time. A TreeSet ordering criterion also decides uniqueness in that implementation.
C18-A01 – Source and Result
Task. Predict the first two lines of StreamDemo.java and indicate which operation creates the new list.
Criterion and solution. The first is [1, 2, 4, 5, 6]; the second is [1, 2, 3, 4, 5, 6, 3]. filter describes selection; toList consumes the stream and materializes a result without modifying the source.
C18-P01 – Windows and Aggregations
Task. Explain why windowFixed(3) produces three groups and what sum teeing prints. Then change the window size to 2 and predict the groups.
Criterion and solution. Seven elements produce windows [1, 2, 3], [4, 5, 6], [3]; the sum is 24. With size 2 we obtain [1, 2], [3, 4], [5, 6], [3]. Both teeing collectors read the same logical sequence to count and sum.
C18-D01 – An Already Consumed Stream
Task. Save data.stream() in a variable and invoke toList() twice on the same variable. Then try calling data.stream() twice in two separate expressions.
Criterion and solution. The same Stream object cannot be consumed twice; the second terminal fails. The List remains available and can produce two distinct streams. The answer distinguishes the pipeline's lifecycle from the collection's.
C18-G01 – Four Questions About the Catalog
Task. Before running StreamCatalogDemo.java, predict sorted available titles, the Computing department's book count, the sum of pages and the available title shortest by pages. Then add an unavailable book with 50 pages: which answers change?
Criterion and solution. Initial results are [Algebra, Algorithms, Java], 3, 1150 and Algebra. If the new book belongs to Computing, department count rises to 4 and page sum to 1200; the available list and available minimum remain unchanged. If you choose another department, you must adjust the count prediction: chosen data is part of the problem.