skip to content

What are the four core functional interfaces in java.util.function, and what is the shape (inputs and output) of each?

level: juniorimportance: must knowfreq 80%

answer

  1. Function = apply, Consumer = accept, Supplier = get, Predicate = test
  2. Shape = inputs + output: 1→value, 1→void, 0→value, 1→boolean
  3. Predicate returns primitive boolean, not Function<T,Boolean>
  4. map=Function, filter=Predicate, forEach=Consumer, orElseGet=Supplier
  5. All are single-abstract-method interfaces (SAM)

basics

~10 s

Function<T,R> takes one value and returns another. Consumer<T> takes one value, returns nothing. Supplier<T> takes nothing, returns a value. Predicate<T> takes one value, returns a boolean.

solid answer

~40 s

The java.util.function package defines four core single-argument interfaces, each a target type for a lambda. Function<T,R> maps an input of type T to an output of type R via apply. Consumer<T> accepts a T and returns nothing (void) via accept — it works by side effect, like printing. Supplier<T> takes no input and produces a T via get, used for lazy or deferred values. Predicate<T> takes a T and returns a boolean via test, used for filtering and conditions. Knowing the shape — how many inputs and whether there is a return — lets you pick the right one: 'transforms one thing into another' is Function, 'consumes' is Consumer, 'produces from nothing' is Supplier, 'tests' is Predicate. They are what stream operations like map, filter, and forEach expect.

code

java · 9 lines
java
Function<String, Integer> length = String::length;   // T -> R
Consumer<String> printer = System.out::println;       // T -> void
Supplier<Double> random = Math::random;               // () -> T
Predicate<String> isEmpty = String::isEmpty;          // T -> boolean

System.out.println(length.apply("hello"));  // 5
printer.accept("side effect only");          // prints, returns nothing
System.out.println(random.get());            // produces a value
System.out.println(isEmpty.test(""));        // true

go deeper

for a junior

Can name the four interfaces and state each one's shape (how many inputs, what it returns) and its single method name.

for a middle

Maps each interface to the stream operation that consumes it (map/filter/forEach) and explains why Predicate is a distinct type from Function<T,Boolean>.

for a senior

Explains the single-abstract-method foundation, lazy evaluation via Supplier (orElseGet vs orElse), and when reusing the core four is cleaner than declaring a custom interface.

for a principal

Frames the catalog as a deliberate API design — minimal core types plus systematic variations — and weighs the readability/boxing trade-offs that justify purpose-built interfaces over a single generic Function everywhere.

## What a functional interface is A **functional interface** is an interface with exactly **one abstract method** (the 'single abstract method', or SAM). Because there is only one method to implement, the Java compiler lets you supply it as a **lambda expression** (`x -> x + 1`) or a **method reference** (`String::length`) instead of writing a full anonymous class. The lambda's parameters and body must match that one abstract method's signature. Java ships a ready-made catalog of these interfaces in the package **`java.util.function`** so you rarely have to declare your own. Four of them are the foundation; everything else in the package is a variation on these. ## The four core interfaces Think of each by its **shape**: *how many inputs* and *whether it returns something*. | Interface | Abstract method | Inputs | Output | Mnemonic | |---|---|---|---|---| | `Function<T,R>` | `R apply(T t)` | one (T) | a value (R) | transforms T into R | | `Consumer<T>` | `void accept(T t)` | one (T) | nothing (void) | consumes/uses a T | | `Supplier<T>` | `T get()` | none | a value (T) | supplies a T from nothing | | `Predicate<T>` | `boolean test(T t)` | one (T) | a boolean | tests a T | - **`Function<T,R>`** — a mapping. `T` is the input type, `R` the result type (they can be the same or different). Example: `Function<String,Integer> len = String::length;` then `len.apply("hi")` is `2`. - **`Consumer<T>`** — does something with its argument and returns nothing. It is useful only for its **side effect** (printing, storing, logging). Example: `Consumer<String> print = System.out::println;` then `print.accept("hi")` prints `hi`. - **`Supplier<T>`** — a factory or deferred value. It takes no argument and yields a `T` each time you call `get()`. Useful for **laziness**: the work happens only when `get()` runs. Example: `Supplier<Double> rnd = Math::random;`. - **`Predicate<T>`** — a boolean-valued test. Example: `Predicate<String> empty = String::isEmpty;` then `empty.test("")` is `true`. Predicates drive filtering. ## Why a separate boolean type A predicate is technically just a `Function<T,Boolean>`, but `Predicate<T>` returns the **primitive** `boolean` (not the boxed `Boolean`), avoiding an object allocation, and it adds combinator methods (`and`, `or`, `negate`). That is the recurring theme of this package: purpose-built types are clearer and often faster than reusing `Function` for everything. ## Where you meet them The Stream API and `Optional` are built on these types: `stream.map(fn)` takes a `Function`, `stream.filter(p)` takes a `Predicate`, `stream.forEach(c)` takes a `Consumer`, and `Optional.orElseGet(s)` takes a `Supplier`. So recognizing the four shapes is really recognizing the vocabulary of functional Java. ## Deriving an answer at any level Given a lambda, ask: *Does it take an argument? Does it return a value?* No argument + returns → `Supplier`. Argument + returns boolean → `Predicate`. Argument + returns another value → `Function`. Argument + returns nothing → `Consumer`. That decision tree reproduces the whole core catalog.

  • Why does Predicate<T> exist when Function<T,Boolean> could do the same job?
    Predicate returns a primitive boolean (no Boolean boxing) and adds boolean combinators (and/or/negate). It is clearer and slightly cheaper, and it is the type the stream filter and Optional.filter operations expect.
  • Which functional interface would you pass to Optional.orElseGet, and why not orElse?
    A Supplier<T>. orElseGet defers the work — the supplier's get() runs only if the Optional is empty — whereas orElse always evaluates its argument eagerly, even when the value is present.

saying these in an interview costs you the question

  • Saying Consumer returns a value — it returns void; it works by side effect
  • Confusing the method names (calling Predicate's method 'apply' instead of 'test')
  • Thinking Supplier takes an argument — it takes none
  • Claiming you must write an anonymous class — a lambda or method reference is the point

context