Is there an easier way to declare a lambda as a variable in java similar to that of Kotlin?

Viewed 72

here's how lambdas are in kotlin -

val myLambda: (Int, Int) -> Unit = { a, b ->
    Log.d(TAG, "sum value = ${a + b}")
}
myLambda(1, 2)//running the lambda

In java, I found these two methods to do the same.

Here, I can't have the runnable take a parameter.

// runnable method
Runnable runnable = () -> {
    System.out.println("x");
};
runnable.run();

The issue with this method is I would have to declare multiple interfaces for different types

// interface method
Finder finder = (s1, s2) -> s1.indexOf(s2);
System.out.println(finder.find("1234", "23"));

public interface Finder {
    public int find(String s1, String s2);
}

So, the question I have is whether there is an easier way to implement lambda in java better that both of these.
Note - I'm new to java.

3 Answers

Contrary to Kotlin, Java isn't a Functional programming language, it's Object-oriented and in addition has a moderate subset of functional features. On the other hand, Kotlin fully supports both Functional and Object-oriented paradigm.

In Kotlin, we can define a function, for instance like this:

val printSquare = { i: Int -> println(i * i) }

And its type would be successfully inferred, the part on the right would be recognized as being of a function type. Kotlin would know that it has operator invoke() which can be used implicitly or explicitly printSquare.invoke(10).

Conversely, in Java something like that would not compile:

var printSquare = (int i) -> System.out.println(i * i); // compiler would not be able to infer the type `printSquare` becuase lambda expression by itself has no type

In Java, there's no function types. Instead, we have a notion of a functional interface.

Functional interface - is an interface which declares a single abstract method (it might also have a bunch of static and default methods, but abstract method should be only one). And every lambda expression or method reference should conform to a particular functional interface, i.e. they have no type by itself, they have to provide an implementation to the interface which would be the target type of lambda (or method reference).

To make the definition of printSquare lambda shown above compile, we to provide the type (which should be a functional interface) and target type of the lambda would be inferred from the assignment context:

IntConsumer printSquare = i -> System.out.println(i * i);

For more information on the type inference in Java, see

Possible ways to interact with Java 8 function would depend on its target type. On printSquare we can invoke accept() and andThen() (andThen is a default method). With Runnable we would have only run at our disposal.

So the key point is that there are no functional types in Java, and in order to define a Java 8 function either as lambda or method reference we need either:

  • Define our own functional interface which would be a target type for the lambda;

  • Use existing functional interface from JDK, some kind of library, or framework.

The following Kotlin function:

val myLambda: (Int, Int) -> Unit = { a, b ->
    Log.d(TAG, "sum value = ${a + b}")
}

can be translated into Java as a BiConsumer:

BiConsumer<Integer, Integer> myLambda = (a, b) -> Log.d(TAG, "sum value = " + (a + b));

The issue with this method is I would have to declare multiple interfaces for different types

Well, it's actually rarely the case when you need to declare a functional interface. Only in the package java.util.function there are over 40functional interfaces at your disposal. And also there are lots and lots of them in other parts of the JDK, the most common are Comparator, Runnable, Callable, etc.

And there are numerous functional interfaces provided by frameworks. Because the ability to implement some functionality with a single line of code makes a life a bit easier, and because some interfaces naturally became lean when their designers respect the Interface segregation principle.

Remember that any interface, even it has been designed prior to Java 8, if it has exactly one abstract method is a functional interface, and therefore eligible to be implemented using lambda.

No. Java does not have function types built into the language. You must have an interface for every lambda you define.

...or you can use the built-in ones, which are sufficient for many use cases. This, for example, might be a ToIntBiFunction<String, String>.

Since Java 8, there is the Generic Function interface. It allows you to store lambda functions.

Related