Course contents

Functional Java basics: interview questions & scenarios

Premium14 questions · 28 what-if follow-ups

These are the lambda and functional-style questions I ask most in Java backend interviews. Half of them are short code puzzles, because a three-line lambda that does not compile, or a stream that prints nothing, tells me quickly whether you understand capture and laziness or have only memorised syntax.

Here's how to use this page: read the question, say your answer out loud first, then open the model answer. The "What if..." follow-ups are the ones I'd ask next, so don't skip them. If a question stumps you, the lesson behind it is in this topic: functional interfaces, callbacks and functional programming.

Question 1. ConceptWarm-upAsked very often

What is a functional interface? Is Comparator one, even though it declares two abstract-looking methods?

Tests single abstract method, @FunctionalInterface, Object methods

Show answerHide answer2 follow-ups

Model answer

A functional interface has exactly one abstract method, and that is the method a lambda or method reference implements. default and static methods do not count because they have bodies, and neither do abstract re-declarations of public Object methods such as equals or toString, since every implementation inherits those from Object anyway (JLS 9.8).

Comparator declares int compare(T, T) and boolean equals(Object). Only compare counts, so Comparator is functional. @FunctionalInterface is optional: it makes the compiler reject the interface if it ever gains a second abstract method, and it documents intent.

How I’d say it in the interview

"One abstract method. Defaults, statics and redeclared Object methods do not count, so Comparator qualifies: its equals is inherited from Object by every implementation. The annotation is a compile-time guard, not a runtime feature."

Signals depth

Naming the Object-method exclusion, and knowing that the annotation has no runtime effect.

Red flags

"An interface with one method" (forgets defaults), or "it must be annotated with @FunctionalInterface".

Follow-ups interviewers ask next

  1. What if I add a second abstract method to an interface annotated @FunctionalInterface?

    The interface itself stops compiling: "Unexpected @FunctionalInterface annotation ... multiple non-overriding abstract methods found". Without the annotation, the interface compiles and every lambda that targets it breaks instead, often far from the change.

    1. What if the interface extends two parents that each declare void run()?

      It's still functional. Both inherited methods have the same signature, so they merge into one abstract method. If the signatures differed, it would have two and stop being functional.

Question 2. DebuggingWarm-upAsked very often

Why doesn't this compile, and how would you fix it?

Tests effectively final, lambda capture

Show answerHide answer2 follow-ups

Model answer

long total = 0;
orders.forEach(o -> total += o.cents());
// error: local variables referenced from a lambda expression must be final or effectively final

A lambda captures the value of a local variable, not the variable itself. Locals live in the method's stack frame, and the lambda may outlive that frame or run on another thread, so Java copies the value into the lambda and forbids changing the variable on either side. total += ... modifies it, so it is not effectively final.

The fix is to stop mutating and let the library compute the result: long total = orders.stream().mapToLong(Order::cents).sum();.

How I’d say it in the interview

"Lambdas capture locals by value, so the local must be effectively final, and += breaks that. I would not fight it with a holder; I'd write it as a reduction: mapToLong then sum."

Signals depth

Explaining why the rule exists (copied values, stack frames, thread safety) and reaching for sum() instead of a workaround.

Red flags

"Wrap it in an int[]" as the first and only answer, or "lambdas cannot use local variables".

Follow-ups interviewers ask next

  1. What if I use an AtomicLong or a long[] holder = {0} instead?

    It compiles, because the reference stays effectively final and you mutate the object it points to. With forEach on a sequential list it works. But the long[] version is a data race under parallelStream(), and both versions hide intent. Use them only when the side effect is genuinely the point, such as counting events in a listener.

    1. What if total were an instance field instead of a local?

      Then it compiles. The lambda captures this and reads this.total on each call; fields have no effectively-final rule. It is still not thread-safe, and it now ties the lambda's lifetime to the whole object.

Question 3. What does it print?Warm-upAsked very often

Which of these lambdas compile: A, B or C?

Tests effectively final, enhanced for, reassignment after capture

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 4. What does it print?CoreAsked very often

What does this stream print?

Tests stream laziness, vertical evaluation, short-circuiting

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 5. What does it print?CoreAsked very often

What does this print, and what's the difference between orElse and orElseGet?

Tests eager vs lazy arguments, Supplier

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 6. ConceptCoreCommonly asked

Name the four kinds of method reference. What's the difference between order::totalCents and Order::totalCents?

Tests bound vs unbound receivers, eager evaluation

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 7. ScenarioCoreCommonly asked

Your checkout service started timing out after a refactor from synchronous code to CompletableFuture.thenApply. Walk me through which thread runs the callback.

Tests CompletableFuture threading, sync vs async callbacks, production timeouts

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 8. DebuggingCoreCommonly asked

Your async notification task throws in production, but there is no stack trace in the logs. Why can that happen with ExecutorService.submit?

Tests async error handling, Future, uncaught exceptions

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 9. CodingCoreCommonly asked

Write a method that takes a list of pricing rules, each a Function<Long, Long>, and returns one function that applies them in order.

Tests higher-order functions, composition, reduce

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 10. ConceptCoreCommonly asked

Is this method pure? How would you make it testable?

Tests pure functions, referential transparency, side effects

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 11. DebuggingSeniorCommonly asked

Your order export endpoint became flaky after someone changed stream() to parallelStream() and kept forEach(result::add). Walk me through the bug.

Tests parallel streams, shared mutable state, collectors

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 12. DesignSeniorCommonly asked

Would you replace every loop in our codebase with streams? When wouldn't you use one?

Tests imperative vs declarative, performance, side effects, recursion

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 13. DebuggingSeniorSometimes asked

Our service's heap grows by about 1 GB a day. The heap dump shows thousands of UserSession objects whose path to GC root goes through a CopyOnWriteArrayList in PriceFeed. What's happening?

Tests listener leaks, bound method references, lifecycle

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Question 14. ConceptSeniorSometimes asked

Is a lambda an anonymous inner class under the hood? What does javac generate?

Tests invokedynamic, LambdaMetafactory, hidden classes, capture

Model answer, how to say it, 2 follow-ups: unlock with the Java Pass

Premium question set

Keep reading with the Java Pass

The rest of this question set is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

From ₹199 · one-time payment · No auto-renewal

Lessons in Functional Java basics