- A Lambda Expression implements a
Functional Interface
. - A Lambda Expression is not another way to write instances of anonymous classes.
- An interface.
- Has only one abstract method.
- Default and static methods do not count.
- Methods from Object Class do not count. I.e.
hashcode(), equals(), toString()
. - May have one abstract methods.
- May have as many default methods
- May have as many static methods
- May have methods from the Object Class.
- May be annotated with the
@FunctionalInterface
annotation.- This just tells the compiler to help me determine if the interface is a functional interface or not.
- If not, it will throw a compiler error.
public interface Supplier<T> {
T get();
}
- The above is a functional interface.
- A Supplier does not take any kind of object and produces any kind of object as long as it matches the
T
type you define when you define the supplier. - The above can be implemented as follows:
public class SupplierExample {
public String getGreeting() {
Supplier<String> supplier = () -> "Hello Artemas";
return supplier.get();
}
}
public interface Consumer<T> {
void accept(T t);
}
- A consumer, consumes any kind of object which is defined on the parameter.
- Has a single method called
accept(T t)
that takes any kind of object and that does not produce or return anything. - The above can be implemented as:
public class ConsumerExample {
public void printValue(String name) {
Consumer<String> nameConsumer = System.out::println;
nameConsumer.accept(name);
}
}
public interface Predicate<T> {
boolean test(T t);
}
- A Predicate will take some object
T
and perform a test with it to produce a boolean valuetrue
orfalse
. - Used in the filtering operations in the Stream API.
- The above can be implemented as the following lambda:
public class PredicateExample {
public List<String> stringNotStartingWithLetterT(List<String> strings) {
Predicate<String> filter = (String someString) -> someString.startsWith("t");
strings.removeIf(filter);
return strings;
}
}
public interface Function<T, R> {
R apply(T t);
}
- Like the Predicate which returns a boolean value, a Function will take in any type of object and return another type of object.
- Used in the
map()
operation in the Stream API. - The above can be implemented as:
public class FunctionExample {
public List<String> getNames(List<User> users) {
Function<User, String> userNames = User::getName;
return users.stream()
.map(userNames)
.collect(toList());
}
}
- What you can put in a lambda, can be returned also in an instance of an anonymous class.
- Lambda expressions are compiled using specific byte code instructions called
invokedynamic
introduced in Java 7. - Ta make lambdas even faster, you want to avoid autoboxing on lambdas (converting
int
toINT
and auto-unboxing which is convertingINT
toint
).
- The
java.util
package has interfaces that are tailored to with primitive types instead of wrapping types. - E.g. you have the
IntPredicate
that takes anint
and returns aboolean
.
@FunctionalInterface
public interface IntSupplier {
int getAsInt();
}
- This can be implemented as follows:
public class IntSupplierExample {
public int getValue() {
IntSupplier supplier = () -> 10;
return supplier.getAsInt();
}
}
@FunctionalInterface
public interface DoubleToIntFunction {
int applyAsInt(double value);
}
- This can be implemented as follow:
public class DoubleToIntFunctionExample {
public int getIntValueBy(double input) {
DoubleToIntFunction intFunction = value -> (int) value * 2;
return intFunction.applyAsInt(input);
}
}