Java 8 Functional Interfaces: Der komplette Guide (java.util.function)
Was ist ein Functional Interface?
Ein Interface mit genau einer abstrakten Methode (SAM – Single Abstract Method). Kann implizit durch Lambda/Method Reference implementiert werden. Annotation @FunctionalInterface sichert dies compile-time ab.
Die 43 Standard-Functional-Interfaces in java.util.function
Kategorisiert nach Arity (Anzahl Parameter) & Rückgabetyp:
1. Basis-Interfaces (1 Parameter, 1 Rückgabe)
| Interface | Methode | Bedeutung |
|---|---|---|
Predicate<T> |
boolean test(T t) |
Prüft Bedingung → boolean. |
Consumer<T> |
void accept(T t) |
Verbraucht T, kein Return. |
Function<T,R> |
R apply(T t) |
Transformiert T → R. |
Supplier<T> |
T get() |
Liefert T ohne Input. |
UnaryOperator<T> |
T apply(T t) |
Spezialfall: Function<T,T>. |
2. Zwei Parameter
| Interface | Methode | Bedeutung |
|---|---|---|
BiPredicate<T,U> |
boolean test(T t, U u) |
Prüft mit zwei Werten. |
BiConsumer<T,U> |
void accept(T t, U u) |
Verbraucht zwei Werte. |
BiFunction<T,U,R> |
R apply(T t, U u) |
Transformiert (T,U) → R. |
BinaryOperator<T> |
T apply(T t1, T t2) |
Kombiniert zwei T → T. |
3. Primitive Spezialisierungen (Performance, kein Boxing)
Für int, long, double gibt es Varianten ohne Generics-Overhead:
- Functions:
IntFunction<R>,LongFunction<R>,DoubleFunction<R>,ToIntFunction<T>,ToLongFunction<T>,ToDoubleFunction<T>,IntToDoubleFunction,IntToLongFunction,LongToIntFunction,LongToDoubleFunction,DoubleToIntFunction,DoubleToLongFunction. - Predicates:
IntPredicate,LongPredicate,DoublePredicate. - Consumers:
IntConsumer,LongConsumer,DoubleConsumer,ObjIntConsumer<T>,ObjLongConsumer<T>,ObjDoubleConsumer<T>. - Suppliers:
IntSupplier,LongSupplier,DoubleSupplier,BooleanSupplier. - Operators:
IntUnaryOperator,LongUnaryOperator,DoubleUnaryOperator,IntBinaryOperator,LongBinaryOperator,DoubleBinaryOperator.
Praxis-Beispiel: Predicate<Integer>
import java.util.*;
import java.util.function.Predicate;
public class PredicateDemo {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
// Alle Zahlen
eval(numbers, n -> true);
// Gerade Zahlen
eval(numbers, n -> n % 2 == 0);
// > 3
eval(numbers, n -> n > 3);
}
static void eval(List<Integer> list, Predicate<Integer> pred) {
for (Integer n : list) {
if (pred.test(n)) System.out.print(n + " ");
}
System.out.println();
}
}
Ausgabe:
1 2 3 4 5 6 7 8 9
2 4 6 8
4 5 6 7 8 9
Eigene Functional Interfaces definieren
@FunctionalInterface
interface Validator<T> {
boolean isValid(T t);
// default/static Methoden erlaubt, aber nur EINE abstract Methode!
}
Validator<String> notEmpty = s -> s != null && !s.isBlank();
Validator<Integer> positive = i -> i > 0;
Best Practices
- Nutzen Sie Standard-Interfaces (
Predicate,Functionetc.) statt eigener – bessere Interoperabilität. - Bei primitiven Typen: Primitive-Spezialisierungen verwenden (vermeidet Boxing).
@FunctionalInterfaceAnnotation hinzufügen – Compiler prüft SAM-Regel.- Method References nutzen, wo möglich (
list::addvsx -> list.add(x)).
Fazit
Das java.util.function Paket bietet einen vollen Baukasten für funktionale Programmierung. Die primitiven Spezialisierungen sind entscheidend für Performance-kritischen Code (Streams, numerische Berechnungen).
Java
- Java Operatoren meistern: Typen, Syntax und praktische Beispiele
- Java Kommentare: Typen, Verwendung und Best Practices
- Java Enhanced For-Schleife meistern: Syntax, Beispiele und Best Practices
- Java Strings meistern: Erstellung, Methoden und Best Practices
- Java-Schnittstellen meistern: Konzepte, Implementierung und Best Practices
- Java anonyme innere Klassen meistern: Definition, Syntax und praktische Beispiele
- Java Try-With-Resources meistern: Automatisches Ressourcenmanagement erklärt
- Java Annotations erklärt: Typen, Platzierung und praktische Beispiele
- Java Assertions: Praktischer Leitfaden zur Fehlererkennung und Code-Reliabilität
- Java Vector verstehen: Verwendung, Funktionen und Vergleich mit ArrayList