When Java 8 was released, lambda phrases were a hot topic. Lambda expressions have been added to JDK version 8 to enhance Java performance by increasing the language’s expressive power.
But, before entering Lambda, we must first know what the user interface is.
What is a user interface?
If a Java interface contains only one abstract method, it is called a functional interface. For example, the Runnable interface of the package; java.lang is a functional interface because it forms only one method, run ().
Example 1: Define a user interface or interface in Java
- import java.lang.FunctionalInterface;
- @FunctionalInterface
- public interface MyInterface {
- double getValue ();
- }
Note: Annotating @ FunctionalInterface is not necessary, but it is wise to use it because the Java compiler forces the defined interface to be a functional interface and should only have an abstract method. In Java 7, the interface was called the Abstract Method Single or SAM type.
SAM was usually run with anonymous classes in Java 7.
Example 2: Run SAM with anonymous classes in Java
- public class FunctionInterfaceTest {
- public static void main (String [] args) {
- new Thread (new Runnable () {
- @Override
- public void run () {
- System.out.println (“I just implemented the Runnable Functional Interface.”);
- }
- }). start ();
- }
- }
The ability to send an anonymous class to the constructor or method made it easy to write Java 7 code with fewer files. However, the structure was still difficult and a lot of code was needed.
Java 8 went one step further, increasing the power of a SAM. Since we know that an interface has only one method, there is no need to define the name of that method when sending it as an argument. The term lambda allows us to do just that.
Familiarity with the term lambda
The term lambda is essentially an unknown or unspecified method and is not executed alone. Instead, it is used to implement the method defined by the interface.
How to define the term lambda in Java?
The term lambda introduces a new syntactic element and operator in Java. The new operator is called the lambda operator or the arrow operator. (->)
Let’s write a simple method that returns only a constant double value.
double getPiValue () {return 3.1415; }
The lambda expression equivalent to the above method is:
() -> 3.1415
In the lambda expression, the left side of the expression specifies the required parameters of the expression, while the right is the body of the lambda, which determines the function of the lambda expression.
Lambda body is of two types.
1- Body with a single phrase
() -> System.out.println (“Lambdas are great”);
2- The body consists of a block of code
() -> {
double pi = 3.1415;
return pi;
}
A lambda expression can have a parameter. For example:
(n) -> (n% 2) == 0
This lambda expression specifies that the value of n is even or odd.
If the body of the lambda is a block of code, you should always return a value. However, if the lambda body is just a phrase, a return value is not required.
Let’s write the Java code with the lambda expression that returns the value of Pi.
As mentioned earlier, the term lambda is not used alone. Instead, the execution of the abstract method defined by the interface constitutes a function.
Example 3: Define the term lambda with the user interface (interface) in Java
We must first define a MyInterface.java user interface:
- import java.lang.FunctionalInterface;
- // This is functional interface
- @FunctionalInterface
- public interface MyInterface {
- double getPiValue ();
- }
Now, let’s take the lambda expression as an example of a functional interface.
- public class LambdaMain {
- public static void main (String [] args) {
- MyInterface myInterface;
- myInterface = () -> 3.1415;
- System.out.println (“Value of Pi =” + myInterface.getPiValue ());
- }
- }
The output is equal to:
Value of Pi = 3.1415
The lambda expression must be consistent with the abstract method. That is, if you assign () -> “3.1415” to the myInterface instance, the code is defective and will not run because by definition in the interface, the string type is not compatible with double.
You probably do not use a lambda phrase like the one above in a real application. Let’s look at another example of a lambda expression that takes parameters.
Example 4: Using the term lambda with parameters in Java
- @FunctionalInterface
- MyInterface {interface
- Reverse string (String n);
- }
- public class ParamLambdaMain {
- public static void main (String [] args) {
- MyInterface myInterface = (str) ->
- String result = “”;
- for (int i = str.length () – 1; i> = 0; i–)
- result + = str.charAt (i);
- return result;
- };
- System.out.println (“Lambda reversed =” + myInterface.reverse (“Lambda”));
- }
- }
Output
Lambda reversed = adbmaL
General functional interface
The above interface only accepts String and returns the String object. However, we can create a public user interface so that any data type can be accepted.
Example 5: How can a user interface accept any type of data in Java?
Let’s see how this is done:
- // GenericInterface.java
- @FunctionalInterface
- interface GenericInterface <T> {
- T func (T t);
- }
Now, GenericInterface is compatible with any lambda expression that takes a parameter and returns a value of the same type.
- // GenericLambda.java
- public class GenericLambda {
- public static void main (String [] args) {
- GenericInterface <String> reverse = (str) -> {
- String result = “”;
- for (int i = str.length () – 1; i> = 0; i–)
- result + = str.charAt (i);
- return result;
- };
- System.out.println (“Lambda reversed =” + reverse.func (“Lambda”));
- GenericInterface <Integer> factorial = (n) -> {
- int result = 1;
- for (int i = 1; i <= n; i ++)
- result = i * result;
- return result;
- };
- System.out.println (“factorial of 5 =” + factorial.func (5));
- }
- }
Output
Lambda reversed = adbmaL
factorial of 5 = 120
Lambda expression and API flow
A new java.util.stream package has been added to JDK8 that allows java programmers to perform operations such as search, filter, map, reduce, or otherwise manipulate collections such as lists.
For example, we have a data stream (a string list) in which each string is a combination of the country name and the country location. Now, we can process this data stream and retrieve only Nepal locations.
Example 6: Demonstrate the use of lambda with the API stream
- import java.util.ArrayList;
- import java.util.List;
- public class StreamMain {
- static List <String> places = new ArrayList <> ();
- // preparing our data
- public static List getPlaces () {
- places.add (“Nepal, Kathmandu”);
- places.add (“Nepal, Pokhara”);
- places.add (“India, Delhi”);
- places.add (“USA, New York”);
- places.add (“Africa, Nigeria”);
- return places;
- }
- public static void main (String [] args) {
- List <String> myPlaces = getPlaces ();
- System.out.println (“Places from Nepal:”);
- // Filter places from Nepal
- myPlaces.stream ()
- .filter ((p) -> p.startsWith (“Nepal”))
- .map ((p) -> p.toUpperCase ())
- .sorted ()
- .forEach ((p) -> System.out.println (p));
- }
- }
Output
Places from Nepal:
NEPAL, KATHMANDU
NEPAL, POKHARA
The API stream allows us to access methods such as filter (), map, and forEach () that can take a lambda expression as input. We can use both built-in Java methods and also define our own expressions based on the method we learned above. This reduces the lines of code dramatically as we saw in the example above.