Basic Usage of Functional Interface in Java 8
Introduction
After couples of Golang articles, I want to bring something different in this article. I want to talk about Java 8 features, which is functional interfaces. This feature comes up in 8th edition due to Java support for functional programming. Also, I will bring a little topic about lambda expression as well, because they both are related.
If you are a Golang or Gokit supporter, need no worry. I still have plenty of ideas to write about it. Just wait for a while :).
What is functional interface?
Basically, functional interface is an interface (of course) which contains only one abstract method. It means, an interface is still a valid functional interface even-tough it has more than one method, as long as the other method is default or static method. Here are samples of valid and invalid of functional interfaces:
1 2 3 4 5 |
// valid functional interface @FunctionalInterface public interface ValidFunctionalInterface { void sayHello(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// valid functional interface @FunctionalInterface public interface AnotherValidFunctionalInterface { void sayHello(); default int getNumber(){ return 1; } static void go(){ System.out.println("Go"); } } |
1 2 3 4 5 6 7 8 |
// invalid functional interface // compile error @FunctionalInterface public interface AnotherValidFunctionalInterface { void sayHello(); void sayGoodBye(); } |
This type of interface is well known as Single Abstract Method (SAM), and most popular implementation by using Anonymous Inner Class implementation. Moreover, with the rise of lambda expression in 8th, the usages of functional interface are raising into a new level beyond OOP style.
Lambda + Functional Interface
As mentioned in the previous paragraph, functional interface almost has no use without lambda expression. By using lambda expression, we can shorten the syntax without having class implementation for target interface.
1 2 3 4 |
// interface declaration public interface First { String sayHi(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// run functional interface public class MainSolution { public static void main(String[] args) { //without lambda doFirst(new First() { @Override public String sayHi() { return "without lambda"; } }); //with lambda doFirst(() -> "lambda"); } public static void doFirst(First first){ System.out.println(first.sayHi()); } } // Output: // without lambda // lambda |
Another example, with abstract method contains input parameter.
1 2 3 4 |
// interface declaration interface Second{ String sayHi(String name); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// test Second interface public class MainSolution { public static void main(String[] args) { doSecond((s) -> "Hello " + s, "Aaron"); } public static void doSecond(Second second, String name){ System.out.println(second.sayHi(name)); } } // output // Hello Aaron |
Since there are common pattern of functional interface implementation, such as operation that takes one input value and return results, Java already provided list of built-in interfaces that you can use directly without re-declaring it again in your code. For instance, my First
interface is already shipped by java.util.function.Supplier
API. So, without I have to create First interface, I can do something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class MainSolution { public static void main(String[] args) { doSupplier(() -> "lambda"); } public static void doSupplier(Supplier<String> s){ System.out.println(s.get()); } } // output: // lambda |
More information about this built-in function, please visit here.
Method Reference
Another cool feature which come with this functional interface thing is method reference. The purpose of this functionality is to make your code clearer. This is because sometimes lambda expression does nothing but call an existing method. Rather doing the lambda call, we can call by referring to the existing method name. You can spot method reference by identifying the double colon (::) operator.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// sample of method reference public class MainSolution { public static void main(String[] args) { //lambda BiFunction<Integer,Integer,Integer> bi = (a, b) -> MainSolution.addNumber(a, b); System.out.println(bi.apply(5, 6)); // method reference BiFunction<Integer,Integer,Integer> bi2 = MainSolution::addNumber; System.out.println(bi2.apply(5, 6)); } public static Integer addNumber(Integer a, Integer b){ return a + b; } } |
In this example, I want to calculate two input numbers and return the sum of them. First I need to create a method to do the calculation and one interface that takes two input parameters and return a value. As you can see, I use java.util.function.BiFunction
for this purpose because it fits my need. Beside using lambda expression, I used method reference as well for calculating the numbers (see line 11-12). Now you can see the code is clearer because it simplifies the way I implement the interface itself.
Conclusion
That’s all the basic usage of functional interface. Just one thing for sure, before you define your own interface, just look at the built-in interface that are already provided by Java itself. Because as an adage says, do not reinvent the wheel :).
See you in the next article. Have a good day!