Functional Java
Lambdas, functional interfaces, method references, generics basics, and Optional.
7 questions
JuniorTheoryVery commonWhat is a functional interface, and why does it enable lambdas?
What is a functional interface, and why does it enable lambdas?
A functional interface declares exactly one abstract method, optionally marked @FunctionalInterface so the compiler enforces that. Because the single method is unambiguous, the interface can be the target type of a lambda or a method reference, which supplies its implementation. Examples are Runnable, Function, and Predicate.
Common mistakes
- ✗Thinking default and static methods break the single-abstract-method rule and disqualify a functional interface
- ✗Believing
@FunctionalInterfaceis mandatory rather than an optional compile-time check - ✗Assuming only a lambda, not a method reference, can target a functional interface
Follow-up questions
- →How do default methods let an interface stay functional while adding behavior?
- →Why does the compiler reject a lambda for an interface with two abstract methods?
JuniorTheoryVery commonWhat is a lambda expression in Java, and what can it capture?
What is a lambda expression in Java, and what can it capture?
A lambda such as (x) -> x * 2 is a concise inline implementation of a functional interface's single abstract method, with parameters on the left and a body on the right. As a closure it can capture local variables from the enclosing scope, but only effectively-final ones — variables never reassigned after initialization. It also sees enclosing fields and this.
Common mistakes
- ✗Trying to capture and reassign a local variable, which fails the effectively-final rule
- ✗Expecting a lambda's
thisto mean the lambda, when it refers to the enclosing instance - ✗Confusing a lambda with an anonymous class that has its own separate scope and
this
Follow-up questions
- →Why does Java require captured local variables to be effectively final?
- →How does a method reference relate to an equivalent lambda expression?
JuniorTheoryCommonWhat are generics in Java, and what problem do they solve?
What are generics in Java, and what problem do they solve?
Generics parameterize a type or method by a type argument such as <T>, so one definition works for many concrete types. They give compile-time type safety — the compiler rejects a wrong element type and inserts casts for you, so you write no manual casts. A bound like <T extends Number> constrains the argument to a type and its subtypes.
Common mistakes
- ✗Expecting a generic type argument to exist at runtime, ignoring that erasure removes it
- ✗Believing generics permit mixing element types instead of enforcing one at compile time
- ✗Trying to use a primitive like
intas a type argument instead of a wrapper class
Follow-up questions
- →What does an upper-bounded wildcard
<? extends T>allow versus a plain<T>? - →Why must a type argument be a reference type and not a primitive?
MiddleTheoryCommonWhat do Function, Supplier, Consumer, and Predicate each do?
What do Function, Supplier, Consumer, and Predicate each do?
They are the four core shapes of java.util.function, told apart by what they take and what they return. Function<T,R> takes one argument and returns a result (apply). Supplier<T> takes nothing and produces a value (get). Consumer<T> takes a value and returns nothing, acting only by side effect (accept). Predicate<T> takes a value and returns a boolean (test). Two-argument and primitive variants such as BiFunction and IntPredicate follow the same pattern.
Common mistakes
- ✗Swapping
SupplierandConsumer, which take nothing and take a value respectively - ✗Expecting
Predicateto return an arbitrary result rather than aboolean - ✗Not knowing the primitive-specialized variants such as
IntPredicatethat avoid boxing
Follow-up questions
- →Why does
Consumerreturn nothing, and how do you chain two of them together? - →Why does
IntPredicateexist alongsidePredicate<Integer>?
MiddleTheoryCommonWhat are the four forms of a method reference in Java?
What are the four forms of a method reference in Java?
There are four: a static method (Integer::parseInt), an instance method of a particular object (out::println), an instance method of an arbitrary object of the type (String::length, where the receiver arrives as the first argument), and a constructor (ArrayList::new). Each one is shorthand for a lambda whose body does nothing but call that method, and it targets a functional interface exactly as the lambda would.
Common mistakes
- ✗Not knowing a constructor can be referenced at all, with
Type::new - ✗Confusing the bound form
out::printlnwith the unboundString::length, whose receiver is the first argument - ✗Thinking a method reference goes through reflection instead of compiling to the same target as a lambda
Follow-up questions
- →Why can a method reference not replace a lambda whose body does more than a single call?
- →How does the compiler tell the bound form apart from the unbound instance-method form?
MiddleTheoryCommonWhat is the Optional container, and how should you use it?
What is the Optional container, and how should you use it?
Optional<T> is a container that either holds a value or is empty, modeling a result that may be absent. It is meant to replace returning null, making absence explicit in the type and steering callers away from a NullPointerException. You access it with map, orElse, or ifPresent rather than unwrapping blindly with get, so the empty case is handled deliberately.
Common mistakes
- ✗Calling
getwithout checking presence, which throwsNoSuchElementExceptionwhen empty - ✗Assigning
nullto anOptionalvariable instead of usingOptional.empty - ✗Using
Optionalfor fields and parameters rather than just return types as intended
Follow-up questions
- →How does
flatMapdiffer frommapwhen a function itself returns anOptional? - →Why is using
Optionalfor a field or method parameter discouraged?
SeniorTheoryOccasionalWhich anti-patterns show up most often in code that uses Optional?
Which anti-patterns show up most often in code that uses Optional?
Calling get() without checking presence, which merely moves the NullPointerException one line down. Putting Optional on fields, parameters or collection elements, when it was designed for return types alone. Assigning null to an Optional variable instead of Optional.empty(). Writing isPresent() then get(), a null check in disguise — prefer map, filter or ifPresent. And using orElse for an expensive fallback, whose argument is evaluated even when a value is present.
Common mistakes
- ✗Treating
get()as a safe accessor rather than an unchecked unwrap that throws when empty - ✗Putting
Optionalon fields and method parameters instead of restricting it to return types - ✗Assuming
orElseis lazy likeorElseGetand handing it an expensive expression
Follow-up questions
- →Why is
OptionalnotSerializable, and what does that mean for an entity field? - →When exactly does
orElseevaluate its argument even though a value is present?