skip to content

Functional & Marker Interfaces

Functional interfaces (one abstract method, optionally marked @FunctionalInterface) that lambdas target, and marker interfaces like Serializable and Cloneable that carry no methods at all. Interviewers ask what makes an interface functional and why markers still exist.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

What is a functional interface in Java, and what does the @FunctionalInterface annotation do?

level: juniorimportance: must knowfreq 78%

answer

  1. SAM = Single Abstract Method
  2. Lambda needs a functional-interface target type
  3. default/static/private/Object methods don't count
  4. @FunctionalInterface is optional but enforces the rule
  5. java.util.function: Function/Predicate/Supplier/Consumer

basics

~20 s

A functional interface is an interface with exactly one abstract method, so it can be implemented by a lambda. @FunctionalInterface is an optional annotation that makes the compiler check that the interface really has just one abstract method.

solid answer

~40 s

A functional interface is an interface with exactly one abstract method (a SAM type). Because there is only one method to implement, the compiler can treat a lambda expression or method reference as an instance of that interface. Examples in the JDK include Runnable, Comparator, Callable, and the java.util.function types like Function, Predicate, and Supplier. The optional @FunctionalInterface annotation documents the intent and asks the compiler to fail the build if the interface ever stops having exactly one abstract method. Importantly, default methods, static methods, private methods, and re-declarations of public methods from java.lang.Object (like equals or toString) do not count toward the single-abstract-method limit, so an interface can have many of those and still be functional.

go deeper

for a junior

Can define a functional interface as 'one abstract method' and knows a lambda implements it; recognizes Runnable and Comparator as examples.

for a middle

Explains precisely which methods don't count (default/static/private/Object), names the java.util.function families, and knows @FunctionalInterface is optional but enforcing.

for a senior

Reasons about lambda target typing and overload resolution, designs custom functional interfaces sparingly (preferring java.util.function), and understands why the annotation guards API stability.

for a principal

Weighs API evolution risk: adding a second abstract method is a breaking change; uses @FunctionalInterface deliberately on published SAM types and chooses standard vs custom interfaces for library ergonomics and binary compatibility.

## What problem this solves Before Java 8, to pass a small piece of behavior to a method (for example, telling `Collections.sort` how to order elements), you had to write a whole anonymous class. That was verbose. Java 8 introduced **lambda expressions** — a compact syntax for an anonymous function — and **method references**. But Java is statically typed: every value must have a type. A lambda has no class of its own, so the language needs to know *what interface* the lambda is implementing. That target type is a **functional interface**. ## Definition An **interface** is a contract: a named set of methods a class promises to provide. An **abstract method** is a method with no body — just a signature — that an implementer must fill in. A **functional interface** is simply an interface that has **exactly one abstract method**. Because there is exactly one method to supply, the compiler can take a lambda (a bare method body) and know it belongs to that single method. The jargon term for this is a **SAM type** (Single Abstract Method). ```java interface Greeter { // functional: one abstract method String greet(String name); } Greeter g = name -> "Hi " + name; // lambda implements greet ``` ## What counts as "the one abstract method" The rule is more precise than "one method total." These do **not** count against the single-abstract-method requirement: - **default methods** — methods in an interface that already have a body (introduced in Java 8). - **static methods** — methods called on the interface itself, not on an instance. - **private methods** — internal helpers (Java 9+). - **public methods that override `java.lang.Object`** — for example, an interface may re-declare `boolean equals(Object)` or `String toString()`. Since every object already inherits these from `Object`, they are not a new abstract method to implement. So an interface can have many default/static methods and still be a valid functional interface, as long as **exactly one** truly-abstract, non-Object method remains. `Comparator<T>` is the classic example: its single abstract method is `compare(T, T)`, yet it has many default and static helpers like `reversed()` and `thenComparing()`. ## @FunctionalInterface `@FunctionalInterface` is an **annotation** — metadata you place above the interface. It is **optional**: an interface is functional based on its shape, not on the annotation. Its job is twofold: 1. **Documentation** — it signals to readers "this is meant to be used as a lambda target." 2. **Compile-time enforcement** — if you add a second abstract method later, the build fails with an error. Without the annotation, adding a second abstract method silently and quietly breaks every lambda that targeted it, but only at the call sites, with a confusing message. With the annotation, the error points right at the interface. ```java @FunctionalInterface interface Transformer { String apply(String s); // adding 'int count();' here would now fail to compile } ``` ## The JDK's standard functional interfaces The package `java.util.function` provides ready-made functional interfaces so you rarely need to invent your own: `Function<T,R>` (takes a T, returns an R), `Predicate<T>` (takes a T, returns boolean), `Supplier<T>` (takes nothing, returns a T), `Consumer<T>` (takes a T, returns nothing), `BiFunction`, `UnaryOperator`, and primitive-specialized variants like `IntPredicate`. Older single-method interfaces — `Runnable`, `Callable`, `Comparator` — are also functional and work with lambdas. ## Why it matters Functional interfaces are the bridge that makes lambdas, method references, and the Streams API possible. Every `stream.map(x -> ...)`, every `list.forEach(System.out::println)`, every `Comparator.comparing(...)` relies on a functional interface as the target type.

  • Can a functional interface declare equals(Object) as an abstract method and still be functional?
    Yes. Methods that override a public method of java.lang.Object (equals, hashCode, toString) do not count as the single abstract method, so the interface can still have one genuine abstract method and remain functional.
  • Is @FunctionalInterface required to use a lambda?
    No. Any interface with exactly one abstract method can be a lambda target. The annotation only adds documentation and a compile-time check; it does not enable the feature.

saying these in an interview costs you the question

  • Saying a functional interface can have only one method total (it can have many default/static methods)
  • Believing @FunctionalInterface is required for lambdas to work
  • Forgetting that re-declared Object methods (equals/toString) don't count toward the SAM limit
  • Confusing 'functional interface' with 'marker interface' (marker has zero methods)

context

open as a page

What is a marker interface in Java? Give examples and explain how it works.

level: juniorimportance: should knowfreq 62%

basics

~20 s

A marker interface is an empty interface with no methods. A class implements it just to 'tag' itself with a property, like being serializable. Code elsewhere checks 'instanceof' to see if the tag is present and behaves differently. Serializable and Cloneable are examples.

open as a page

How does the compiler decide which functional interface a lambda or method reference implements, and why can the same lambda satisfy multiple functional interfaces?

level: seniorimportance: should knowfreq 45%

basics

~20 s

A lambda has no type of its own. The compiler looks at the context where the lambda is used — the variable type, the method parameter, or the return type — to find the expected functional interface, then checks the lambda matches that interface's single method. The same lambda fits any interface whose method has a compatible shape.

open as a page

Marker interfaces vs annotations for tagging types: what are the trade-offs, and when would you choose each?

level: seniorimportance: should knowfreq 48%

basics

~20 s

A marker interface tags a type and gives you a real type the compiler can use (e.g. require it as a method parameter). An annotation can tag types, methods, or fields and can carry data, but doesn't create a type for compile-time checks. Use a marker for type-level guarantees; an annotation for richer metadata.

open as a page

As a marker interface, what hidden contract and design risks does implementing java.io.Serializable impose?

level: principalimportance: nice to knowfreq 33%

basics

~20 s

Serializable looks like a harmless empty tag, but implementing it secretly makes your object's private fields part of a public, long-lived format. That makes the class hard to change later, opens security holes when reading untrusted bytes, and weakens encapsulation. So you should add it deliberately, not by habit.

open as a page