Java Module 26
Advanced language and platform features interview questions
Interview questions on advanced language and platform features: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What is data-oriented programming in Java, and which language features support it?
Answered in the lesson Data-oriented programming with records
-
Fresher to mid
What does a switch with patterns do when its selector is null, and how do you handle null on purpose?
-
Fresher to mid
What does @Retention control, and why can reflection not see an annotation declared without it?
Answered in the lesson Annotations and annotation processing
-
Fresher to mid
What are elements, builders and transforms in Java's Class-File API?
-
Fresher to mid
What are a species, a lane and a tail in Java's Vector API?
-
Fresher to mid
What is reflection in Java, and why should application code use it sparingly?
Answered in the lesson Reflection, method handles and VarHandles
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Mid to senior
An order service models 14 kinds of order event as subclasses with a visitor interface, and every new event touches nine visitor classes. A colleague proposes sealed records with pattern switches instead. How would you decide, and how would you migrate safely?
- What it tests
- The trade-off between adding types and adding operations, what visitors and exhaustive switches each check, the limits sealing puts on other modules, and a stepwise migration.
- First step
- Ask which change is more frequent: a new kind of event or a new operation over events. Both designs give compile-time completeness, a visitor through its abstract methods and a switch through exhaustiveness, so the question is cost and reach. Then check whether code outside the module implements the event type, because sealing would forbid it.
- Follow-ups
-
- Two other teams write their own event classes.
- Some visitors keep state across events.
- How do you migrate without one big change?
From the lesson Data-oriented programming with records
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Fresher to mid
A service returns a Result class with the fields status, data and errorMessage. Every few weeks a bug reads data when status is FAILED and shows an empty screen or throws NullPointerException. How would you remodel the result with Java 25 features, and how do the callers change?
- What it tests
- Making illegal states unrepresentable with sealed records, validating in compact constructors, exhaustive handling at call sites, and migrating callers and the wire format.
- First step
- List the outcomes and the data each one really has: a success with data, a failure with a reason, perhaps a not-found with nothing. Count what the current class allows: three statuses times two possible nulls in each of two fields is 12 combinations, of which 3 are meaningful. Each real outcome becomes a record of a sealed interface.
- Follow-ups
-
- Callers in another repository still read the old fields.
- Some failures may be retried and some may not.
- How do you send the new type as JSON?
From the lesson Data-oriented programming with records
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
After a routine dependency upgrade, a payment service throws java.lang.MatchException from a switch that nobody changed, and only for some requests. What do you suspect, how do you confirm it, and what do you change so that it cannot happen again?
- What it tests
- Separate compilation and exhaustiveness, reading MatchException and its cause, new subtypes against throwing accessors, and build habits that turn the gap into a compile error.
- First step
- A MatchException comes from a switch that javac accepted as exhaustive, so start from what changed: the classes the switch meets at run time. Read the stack trace and the exception's cause, then compare the types the switch covers with the ones the upgraded library can now hand it.
- Follow-ups
-
- The exception has a cause, an IllegalStateException thrown by an accessor.
- Twelve services share the library. How do you roll the change out?
- Should the switch get a default branch now?
From the lesson Pattern matching deep dive
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A support-ticket router is one switch over a Ticket record with seven guarded cases. A new rule for priority customers was added at the bottom, compiles cleanly, and never fires. Why did javac not catch it, how do you find such dead rules, and how would you restructure the switch?
- What it tests
- Knowing that guards never dominate, why javac cannot compare conditions, testing and coverage of guarded cases, and turning a growing list of rules into data.
- First step
- javac reports a dominated case only when an earlier case without a guard covers its pattern; it never compares guards, because in general it cannot tell whether two conditions overlap. So an earlier guard that holds for every priority ticket takes them all. Run the router on a few priority tickets and log which case fires for each.
- Follow-ups
-
- How would a test suite catch the next dead rule?
- Product owners change the rules every week.
- Can reordering the cases change the result for other tickets?
From the lesson Pattern matching deep dive
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A teammate wants to turn on primitive type patterns in a JDK 25 service, to replace the manual range checks that run when amounts are parsed. What do you tell them about preview features, and what would you do instead today?
- What it tests
- What a preview feature commits a project to, with flags, class file versions and changing rules, and final APIs for exact conversions with their edge cases.
- First step
- Start with what a preview feature is: complete but not permanent, switched on with --enable-preview when compiling and when running, and free to change in the next release. Then list what the range checks must guarantee, and which final APIs already give that guarantee.
- Follow-ups
-
- The service moves to the next LTS release once a year.
- Which edge cases must the replacement checks handle?
- How would you try the feature without risking production?
From the lesson Pattern matching deep dive
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
After moving a project from JDK 21 to JDK 25, the build fails with "cannot find symbol" for classes that an annotation processor used to generate, although nobody changed the processor or the build file. What happened, and how do you fix the build properly?
- What it tests
- How javac finds and enables annotation processors, reading an error that points at the wrong place, and configuring processors in builds.
- First step
- The missing classes are the processor's output, so the first question is whether the processor ran at all. Compare the javac command line and everything javac printed in the last JDK 21 build with the first JDK 25 build, and check how the build tells javac where its processors are.
- Follow-ups
-
- Why is -proc:full not the best fix?
- The processor needs two libraries of its own. Where do they go?
- How do you stop this kind of silent change in future upgrades?
From the lesson Annotations and annotation processing
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An auditing library reads a custom @Audited annotation at run time. After a refactor that introduced interfaces, a base class and proxies, it ignores @Audited on some services, with no error. List the likely causes and how you would confirm each one.
- What it tests
- Retention and targets, what @Inherited does and does not cover, proxies and subclasses, repeatable containers, and reproducing a silent failure with small reflection probes.
- First step
- Write a ten-line probe that prints getAnnotations() for one ignored service class, its methods, its superclass and its interfaces, and run it in the same deployment. Then compare where the annotation was written with where the library looks: on the class or on a method, and on the class itself or on the proxy.
- Follow-ups
-
- The annotation is on an interface method that the service implements.
- The framework wraps each service in a generated subclass.
- Some services carry @Audited twice, with different reasons.
From the lesson Annotations and annotation processing
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
A service maps 300 annotated record types to CSV and JSON, and it must start in under one second on small containers. Would you read the annotations with reflection at start-up or generate the mappers with an annotation processor? Defend the choice with numbers.
- What it tests
- Estimating start-up and per-call costs, compile-time against run-time errors, build complexity, and the trade-offs of generated code.
- First step
- Estimate both costs. Reflection-based mapping must scan or register 300 types, read their components and annotations and prepare accessors on every start; generated mappers do that work once, in the build. Measure one type's reflective set-up time, multiply by 300, and compare it with the one-second budget.
- Follow-ups
-
- Some record types come from plugins that are loaded at run time.
- How do you test generated code?
- What does the choice mean for error messages when an annotation is used wrongly?
From the lesson Annotations and annotation processing
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A build plugin reads every compiled class with java.lang.classfile to check coding rules. The day the team moves its compiler to JDK 27, the plugin, which runs on JDK 25, fails with "Unsupported class file version: 71". What is happening, and what are your options?
- What it tests
- How the JDK's class-file API ties readable versions to the running JDK, class-file version numbers, and choosing between a newer runtime for the tool, the release option and another library.
- First step
- Read the number first: class-file version 71 is Java 27, and JDK 25's API accepts at most 69, which ClassFile.latestMajorVersion() confirms. The API reads class files of its own JDK and older ones, never newer ones. So either the plugin runs on a JDK at least as new as the compiler, or the code is compiled for an older release.
- Follow-ups
-
- Would compiling with --release 25 on JDK 27 fix it, and what does that cost?
- The plugin must also work for teams that are still on JDK 21.
- How should the plugin report this failure to its users?
From the lesson Reading and writing class files
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
Your Java agent uses the Class-File API to add a timing call at the start of every method. It passes its own tests, but one service now fails at start-up with VerifyError in a class from a third-party library. How do you find the cause, and how do you make the agent safe?
- What it tests
- Bytecode verification, stack-map generation and class hierarchy resolution in transforms, the contract of a ClassFileTransformer, and testing instrumentation against real libraries.
- First step
- Capture the exact bytes: log the failing class and save what the agent returned for it, then run ClassFile.verify on those bytes and compare javap -c -v of the original and the transformed class. A VerifyError means the agent returned invalid bytecode, so the bug is in what the transform emitted or in the stack maps built for it.
- Follow-ups
-
- The failing methods are all constructors.
- The library is loaded by a custom class loader.
- What should the agent do with a class it cannot transform safely?
From the lesson Reading and writing class files
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
You maintain an open-source library that generates small adapter classes at run time with ASM and supports JDK 17, 21 and 25. A contributor proposes replacing ASM with java.lang.classfile. Would you merge it, and how would you plan the change?
- What it tests
- Where the Class-File API is available, what version skew costs a bundled library, multi-release JARs, and a migration plan that keeps older JDKs working.
- First step
- Start from the support matrix: java.lang.classfile exists only on JDK 24 and later, so on JDK 17 and 21 the library still needs ASM. The decision is not all or nothing: a multi-release JAR can carry the ASM generator for old JDKs and a Class-File API generator in a versioned directory for 25, behind one internal interface.
- Follow-ups
-
- How do you test that both generators produce equivalent classes?
- What would let you drop ASM completely?
- Does the change help a library that only writes classes and never reads newer ones?
From the lesson Reading and writing class files
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
A colleague rewrote an element-wise loop that scales prices, using the Vector API, and the benchmark shows no speed-up at all. The code is correct. What are the likely explanations, and how would you check each one?
- What it tests
- Knowing that C2 auto-vectorises simple loops, benchmarking against the right baseline, and checking the JIT settings, the data size and the hardware.
- First step
- Suspect first that C2 had already vectorised the plain loop: element-wise loops over arrays are exactly what its auto-vectoriser handles. Check by running the same benchmark with -XX:-UseSuperWord. If the plain loop slows down sharply while the Vector API version does not, the JIT was doing the work already.
- Follow-ups
-
- The benchmark runs on a CI machine with 2 virtual CPUs.
- The arrays hold 50 million elements.
- When would you keep the Vector API version anyway?
From the lesson SIMD with the Vector API (incubator)
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Mid to senior
After a daily-sales report was vectorised with the Vector API, its float totals differ from the old scalar report in the last digits, and for one large region by several thousand rupees. Is the vector code wrong, and what do you change?
- What it tests
- Floating-point non-associativity, what reordering a reduction does, why money needs exact types, and making scalar and vector results agree when they must.
- First step
- Neither version is wrong by float rules: the vector code adds the same numbers in another order, four lane totals combined at the end, and float addition is not associative. A difference of thousands means the totals are far beyond what float can hold exactly, about 7 significant digits, so the real bug is keeping money in float.
- Follow-ups
-
- Auditors require the new report to match the old one exactly.
- Would double be enough?
- Can an integer version still use SIMD?
From the lesson SIMD with the Vector API (incubator)
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes
-
Senior to staff
Your team measured a threefold speed-up in an image-filter service by using jdk.incubator.vector on JDK 25. The service deploys weekly and must keep working through JDK upgrades. Would you ship it, and under what conditions?
- What it tests
- The incubator contract, launcher and packaging options, a fallback design, performance checks across JDK releases and hardware, and who owns the risk.
- First step
- Treat the API as code that will change: JEP 11 says incubating packages are renamed when promoted, and every JDK release brings a new incubator round. Ship it only behind an interface with a scalar fallback, with the module detected at start-up, and with equality tests and benchmarks that run on every JDK the service may move to.
- Follow-ups
-
- The container image is built with jlink.
- After a JDK upgrade the vector path is slower than the scalar one.
- Who should own the decision to keep or remove the vector path?
From the lesson SIMD with the Vector API (incubator)
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
After an upgrade from JDK 11 to JDK 25, a service fails at start-up with InaccessibleObjectException: "Unable to make field private final byte[] java.lang.String.value accessible: module java.base does not opens java.lang to unnamed module". What does it tell you, and what are your options, from the quickest to the best?
- What it tests
- Strong encapsulation of JDK internals, reading the exception, --add-opens as a stopgap, and replacing the dependency on internals with supported APIs.
- First step
- Read the message as a sentence: some code called setAccessible on a private field of java.lang.String, and since JDK 17 the java.base module no longer opens java.lang to code on the class path. Find the caller in the stack trace; it is usually a library, not the service itself.
- Follow-ups
-
- The code that does it is a library you cannot change this quarter.
- Why did JDK 11 only print a warning?
- How do you find every such access before production?
From the lesson Reflection, method handles and VarHandles
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Senior to staff
A profile of a busy API shows 30 % of CPU time in an in-house reflection-based serializer. How would you make it faster, which changes would you measure first, and how would you prove the gain?
- What it tests
- Where reflective cost comes from, caching lookups per class, constant method handles, generated code, and honest benchmarking with JMH and production measurements.
- First step
- Find out what the serializer does for every object it writes: does it ask the class for its fields or methods, or create method handles, each time? Then profile one request type with JDK Flight Recorder to see whether the time goes to finding members, to calling them or to boxing their values.
- Follow-ups
-
- The serializer already caches Method objects in a HashMap.
- Would generated code be faster still?
- How do you show that the gain holds in production?
From the lesson Reflection, method handles and VarHandles
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Senior to staff
After moving a service to JDK 26, its logs show warnings that a final field "has been mutated reflectively" by a dependency. What is happening, what will break in later releases, and how do you plan for it?
- What it tests
- JEP 500 and the plan to make final mean final, the options that control it, finding the code that mutates finals, and supported alternatives for libraries.
- First step
- The warning names the class and the final field that were written, so start by finding the code that writes them and why: a test run with a stack trace for each write shows the callers. Then read the JDK Enhancement Proposal that introduced the warning, to learn what later releases will do.
- Follow-ups
-
- The dependency is a serialization library.
- Should you just add --enable-final-field-mutation=ALL-UNNAMED?
- Why does the JDK care whether final fields change?
From the lesson Reflection, method handles and VarHandles
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes