Appearance
Lesson 01 · Lambdas & Functional Interfaces
Objectives
After this lesson you will be able to:
- Write lambda expressions and explain what a functional interface is.
- Use the standard
java.util.functioninterfaces. - Use the four kinds of method reference and the variable capture rules.
Functional interfaces and lambda syntax
A functional interface has exactly one abstract method (the SAM). A lambda is a concise instance of one. @FunctionalInterface makes the compiler enforce the "single abstract method" rule.
java
@FunctionalInterface
interface Transformer { int apply(int x); }
Transformer t = x -> x * 2; // lambda
Transformer u = (int x) -> { return x * 2; }; // explicit type + block body
Runnable r = () -> System.out.println("hi"); // no paramsGotcha
default, static, and private methods don't count toward the SAM total, and methods that override Object (equals, toString, hashCode) don't either — so an interface can have those and still be functional.
The java.util.function toolkit
Memorize these shapes — the exam uses them constantly:
| Interface | Abstract method | Shape |
|---|---|---|
Supplier<T> | T get() | () → T |
Consumer<T> | void accept(T) | T → () |
Function<T,R> | R apply(T) | T → R |
Predicate<T> | boolean test(T) | T → boolean |
UnaryOperator<T> | T apply(T) | T → T |
BiFunction<T,U,R> | R apply(T,U) | (T,U) → R |
BinaryOperator<T> | T apply(T,T) | (T,T) → T |
java
Supplier<String> s = () -> "hi";
Predicate<String> empty = String::isEmpty;
Function<String,Integer> len = String::length;
BiFunction<Integer,Integer,Integer> add = Integer::sum;Method references
A method reference names a method that fits the functional interface, in four flavors:
java
str -> str.length() → String::length // instance method of an arbitrary object
() -> new ArrayList<>() → ArrayList::new // constructor
x -> Math.abs(x) → Math::abs // static method
() -> obj.run() → obj::run // instance method of a specific objectVariable capture
A lambda can capture local variables, but only effectively final ones (like inner classes). It can freely read/write fields. A lambda's this refers to the enclosing instance — not the lambda itself (unlike an anonymous class).
java
int factor = 3; // effectively final
Function<Integer,Integer> f = n -> n * factor;
// factor = 4; // would break it: factor no longer effectively final → compile errorSDET note
Lambdas and method references are the backbone of stream pipelines and fluent assertion libraries (assertThat(x).matches(predicate)). Prefer a method reference when it reads clearly (User::name) and a lambda when you need a small expression — both keep test code declarative.
Key Takeaways
- A functional interface has one abstract method;
default/static/private/Objectmethods don't count. A lambda implements it concisely. - Know the
java.util.functionshapes:Supplier,Consumer,Function,Predicate,UnaryOperator,BiFunction,BinaryOperator. - Method references come in four kinds:
Type::instanceMethod,Type::new,Type::staticMethod,obj::instanceMethod. - Lambdas capture only effectively final locals; their
thisis the enclosing instance.
Lesson Quiz
Which interface has the abstract method boolean test(T)?
Is this a valid functional interface?
interface X { int f(); default int g() { return 1; } String toString(); }Which lambda is equivalent to String::length?
Why won't this compile?
int factor = 3; Function<Integer,Integer> f = n -> n * factor; factor = 4;
Inside a lambda, what does this refer to?
Next: Streams Basics. Run the matching code in labs/src/main/java/com/jse21/m06_streams/.