FUNCTIONAL INTERFACES
There are many ways to use a functional interface:
Example 1:
public class Main {
public void myMethod() {
for (; ; )
System.out.println("my Method");
}
public static void main(String[] args) {
// Anonymous method syntax
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Anonymous method");
}
}
).start();
// method reference
Main main = new Main();
new Thread(
main::myMethod
).start();
// lambda expression
new Thread(
() -> System.out.println("lambda expression")
).start();
}
}
Example 2:
Here we can see two types of lambda expressions: single line and block lambda. For the block lambda, we have to write parameter types and also a return keyword is mandatory. There is nothing difficult regarding these language features, it's all about knowing the syntax.
public class Main {
public static void main(String[] args) {
File directory = new File("./src/main/java");
// Anonymous inner class
String[] names = directory.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".java");
}
});
// lambda expression (single line)
String[] names2 = directory.list((dir, name) -> name.endsWith(".java"));
// lambda expression (multiple statements possible)
String[] names3 = directory.list((File dir, String name) -> {
return name.endsWith(".java");
});
// inner class
String[] names4 = directory.list(new MyFilter());
}
public static class MyFilter implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
return false;
}
}
}
Example 3:
// Lambda expression
Stream.of(3, 1, 4, 1, 5, 9).forEach(x -> System.out.println(x));
// Method reference
Stream.of(3, 1, 4, 1, 5, 9).forEach(System.out::println);
// Use a variable
Consumer printer = System.out::println;
Stream.of(3, 1, 4, 1, 5, 9).forEach(printer);
@FunctionalInterface annotation
It is not mandatory but we can use FunctionalInterface annotation for our interface that has 1 abstract method. The benefit is that we will have compile time error if the interface has zero or multiple methods. A functional interface can have static methods or default methods.
Example 4:
@FunctionalInterface
public interface MyInterface {
int myMethod();
default String sayHello() {
return "Hello, World!"; }
static void myStaticMethod() {
System.out.println("I'm a static method in an interface"); }
}
What are "Default Methods" in Java 8?
Before Java 8, an interface could not have a method with an implementation. Implementers had to implement all methods of an interface, so adding a new method to the interface was always affecting the implementers. In Java 8, an interface can have many default methods with bodies and they dont have to be implemented.
java.util.function package
Some functional interfaces are defined in this package.
Consumers: They take an argument and return nothing.
Suppliers: They dont take any arguments and they return a value.
Predicates: They take an argument and return a boolean value.
Functions: They take arguments and return a value.
Example 5: foreach method takes a Consumer as an argument:
public class Main {
public static void main(String[] args) {
List strings = Arrays.asList("this", "is", "a", "list", "of", "strings");
// anonymous "Consumer"
strings.forEach(new Consumer() {
@Override
public void accept(String s) {
System.out.println(s); }
});
// lambda
strings.forEach(x -> System.out.println(x));
// method reference
strings.forEach(System.out::println);
}
}
Some examples are taken from this excellent book:
Modern Java Recipes - Ken Kousen
http://a.co/d/4witmpA
Comments