Why Do I Need a Functional Interface to Work with Lambdas

Why do I need a functional Interface to work with lambdas?

When you write :

TestInterface i = () -> System.out.println("Hans");

You give an implementation to the void hans() method of the TestInterface.

If you could assign a lambda expression to an interface having more than one abstract method (i.e. a non functional interface), the lambda expression could only implement one of the methods, leaving the other methods unimplemented.

You can't solve it by assigning two lambda expressions having different signatures to the same variable (Just like you can't assign references of two objects to a single variable and expect that variable to refer to both objects at once).

Why functional interface used in Java Lambda expression

But just wondering whey Java don't provid some types (Function or Lambda) to define lambda expression e.g. Lambda l = () -> xxxxxx;

IMHO, there are few reasons not to provide new type (interface basically):

  • Because child function is function interface so the Function / Lambda interface must be a Marker Interface. In this case FunctionalInterface annotation does same, even better job. We have it here: https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html
  • But why we choose annotation instead of marker interface even they share same meaning? If you have Function / Lambda interface, that is mean all instances are interchangeable. And when initial lambda, how Java could know which interface function to apply? It is problem.

What are functional interfaces used for in Java 8?

@FunctionalInterface annotation is useful for compilation time checking of your code. You cannot have more than one method besides static, default and abstract methods that override methods in Object in your @FunctionalInterface or any other interface used as a functional interface.

But you can use lambdas without this annotation as well as you can override methods without @Override annotation.

From docs

a functional interface has exactly one abstract method. Since default
methods have an implementation, they are not abstract. If an interface
declares an abstract method overriding one of the public methods of
java.lang.Object, that also does not count toward the interface's
abstract method count since any implementation of the interface will
have an implementation from java.lang.Object or elsewhere

This can be used in lambda expression:

public interface Foo {
public void doSomething();
}

This cannot be used in lambda expression:

public interface Foo {
public void doSomething();
public void doSomethingElse();
}

But this will give compilation error:

@FunctionalInterface
public interface Foo {
public void doSomething();
public void doSomethingElse();
}

Invalid '@FunctionalInterface' annotation; Foo is not a functional
interface

Lambda can only be used with functional interface?

No. There is no way to "overcome" this. A functional interface must have only one abstract method. Your interface has two:

interface Intf<T> {
public T get1(T arg1);
public T get2(T arg1);
}

Note: You don't need to annotate your interface as mentioned in comments. But you can use the @FunctionalInterface annotation to get compile time errors if your interface is not a valid functional interface. So it brings you a little bit more security in your code.

For more see e.g. http://java.dzone.com/articles/introduction-functional-1

Java Functional Interfaces and Lambda Expressions

A lambda expression is a concise way to create an instance of a functional interface, which is an interface with one abstract method. Here, X is a functional interface, with abstract method bar(). You could implement X with:

class XImpl implements X { 
public String bar() { return "Foo"; }
}

X instance = new XImpl();

or an anonymous class

X anon = new X() { 
public String bar() { return "foo"; }
};

or a lambda

X lambda = () -> "foo";

Each of these instantiates an implementation of X. What may be confusing you is the concision of the lambda; because X has only one abstract method, bar, you don't have to say you are implementing bar -- the compiler figures it out. Since bar() takes no arguments and returns String, the compiler ensures that the shape of the lambda is compatible with the shape of the sole abstract method.

Because an X has a bar() method,
you can call it on each of these instances:

String s1 = instance.bar();
assertEquals(s1, "hello");

String s2 = anon.bar();
assertEquals(s2, "hello");

String s3 = lambda.bar();
assertEquals(s3, "hello");

and you get the same result for each.

How come lambda expressions are objects in Java?

You need to understand few things:

1) Functional interface

  • interface which has only one public method
public interface Runnable{
void run();
}
  • this is example of functional interface, it can have different kinds of methods such as int processNumber(int number)
  • just remember there can be only one method (one not implemented method, defaults do not count)

2) Using functional interface

  • you can implement your functional interface in your class let's say MyRunnable
public class MyRunnable implements Runnable{
public void run(){
System.out.println("Hello world");
}
}
  • than you can pass your MyRunnable class in another methods its just normal object
public class MyClass{
public void myMethod(Runnable runnable){
runnable.run();
}
}
  • this would print "Hello world"
public static void main{
MyClass myClass = new MyClass();
myClass.myMethod(new MyRunnable());
}

3) What lambda is doing

  • so what lambda let you do is to create anonymous implementation of interface
public static void main{
MyClass myClass = new MyClass();
myClass.myMethod(() -> System.out.println("Hello my world"));
}
  • this would print "Hello my world"
  • you are just creating anonymous implementation of Runnable and passing it to MyMethod
  • it is just syntactic sugar for this
public static void main{
MyClass myClass = new MyClass();
myClass.myMethod(new Runnable{
public void run(){
System.out.println("Hello my world");
});
}

Purpose of Functional Interfaces in Java8

Obviously you can skip using these new interfaces and roll your own with better names. There are some considerations though:

  1. You will not be able to use custom interface in some other JDK API unless your custom interface extends one of built-ins.
  2. If you always roll with your own, at some point you will come across a case where you can't think of a good name. For example, I'd argue that CheckPerson isn't really a good name for its purpose, although that's subjective.

Most builtin interfaces also define some other API. For example, Predicate defines or(Predicate), and(Predicate) and negate().

Function defines andThen(Function) and compose(Function), etc.

It's not particularly exciting, until it is: using methods other than abstract ones on functions allows for easier composition, strategy selections and many more, such as (using style suggested in this article):

Before:

class PersonPredicate {
public Predicate<Person> isAdultMale() {
return p ->
p.getAge() > ADULT
&& p.getSex() == SexEnum.MALE;
}
}

Might just become this, which is more reusable in the end:

class PersonPredicate {
public Predicate<Person> isAdultMale() {
return isAdult().and(isMale());
}

publci Predicate<Person> isAdultFemale() {
return isAdult().and(isFemale());
}

public Predicate<Person> isAdult() {
return p -> p.getAge() > ADULT;
}

public Predicate<Person> isMale() {
return isSex(SexEnum.MALE);
}
public Predicate<Person> isFemale() {
return isSex(SexEnum.FEMALE);
}
public Predicate<Person> isSex(SexEnum sex) {
return p -> p.getSex() == sex;
}
}


Related Topics



Leave a reply



Submit