Pages

Wednesday, September 11, 2019

Complete Guide to Java 8 Lambda Expressions

1. Overview

In this tutorial, We will learn Java 8 new features about Lambda Expressions step by step in-depth.

Lambda word came from lambda calculus which is used to describe computations. We will go through one by one as below topics today.

Definition
Comparing to Older Java Versions
Lambda Syntax
Lambda Valid Examples
Lambda Rules
Where to Use Lambda
Lambda Sorting Example
Invalid Lambda Expressions
Complete Guide to Java 8 Lambda Expressions
We have already shown few examples on Java 8 Examples Programs Before and After Lambda & Streams. Go through this article before continuing further on this tutorial. If you have basic understanding of lambda's then you are good to continue.

2. Definition


Lambda Expression can be explained as an anonymous function without having a name and passing this anonymous function to another method as an argument.

Anonymous method does not have name but it has list of method arguments, body, return type and valid list of exceptions that can be thrown. 

Lambda Expression will become more concise because this will avoid lots of boiler place coding.

This can be passed as an argument to a method or store in a variable.

If you do not understand at this point, please do not worry. You will definitely understand after reading this complete tutorial.

3. Comparing to Older Java versions


Many developers have a doubt why this concept is introduced in Java 8, not in prior versions of java. And also what is the importance of Lambda?

In java 8 using lambda makes us not write clumsy code using anonymous classes to benefit from behavior parameterization.

Behavior parameterization means passing our logic to a method as a argument.

Note:
Lambdas technically don’t let you do anything that you couldn’t do prior to Java 8. Whatever can be done in older version of Java are same can be done in java 8 also. This just makes us to focus only the core business logic instead of writing tedious syntax.

Now code will become more readable and flexible.

4. Lambda Syntax

Now, We'll take a look at the Lambda syntax.

(lambda parameters) -> (lambda body);

Lambda has mainly three pars.

a) lambda Parameters
b) Lambda Symbol
c) Method body

Here lambda parameters are optional. This is similar to the method arguments. A number of arguments from 0 to N. Parenthesis are mandatory.

Lambda is defined by the symbol '->' (Arrow mark). separates the list of parameters from the body of the lambda.

Next lambda body is similar to the method body. If this is a single line then no need to use the curly braces. We need to write the core logic in the lambda body.

We will learn more about Lambda rules in this further tutorial. For now, take a look at the below simple example.

Interface interf = (int number) -> (System.out.println("Given number "+number));

In the above example program, We are passing a number as an argument to lambda and printing the same value. On the left side, assigned Lambda to a functional interface that is perfectly legal. You will learn more about later in this article.

5. Lambda Valid Examples

We will see valid lambda examples. See more examples on java.util.Stream package.


5.1 Getting String length

(String str) -> str.length();

Here this takes one parameter of type string. This also returns a value that is int type. But, we can not see the returned type because not declared anywhere in the declaration. It is applied internally based on the lambda body. If lambda has only one statement and that hold value that becomes as a return type.

5.2 Employee Rating check


(Employee emp) -> emp.getGrade().equals("A");

Takes one parameter of type Employee and returns boolean. Lambda Body checks grade equal to the "A" then returns true or false.

5.3 Concatenate two strings and print output


(String str1, String str2) -> {
                               String output = str1.concat(str2);
          System.out.println("Concantenated string "+output);
         }

Takes two String parameters and returns nothing. That means the return type is void. The body has two statements that concatenate and prints the output string.

6. Lambda Rules

As of have seen a few examples but you still may have some queries. Now we will see all the rules here that make clear for us.

6.1 Parameters are optional. It can be zero or more.

 () -> {System.out.println("Hello World");};
 (int a) -> {System.out.println("value "+a);};

6.2 If no parameters are available then we need to use empty parenthesis ().

() -> {System.out.println("Hello World");};

6.3 If we have multiple parameters then need to separate them with a comma(,)

(int a, int b) -> System.out.println("sum "+(a+b));

6.4 if the body has the only statement then curly braces are optional.

 (int a) -> System.out.println("value "+a);

6.5 if the body has more than one statement then curly braces are mandatory.

 () -> {
   System.out.println("Hello World");};
   System.out.println("value "+a);
    };

6.6 parameter type(s) is optional. No need to declare manually because compile can expect based on the context. We will discuss more in the next post.

 (a) -> System.out.println("value "+a);
 (a, b) -> System.out.println("sum "+(a+b));

6.7 If only one parameter is available then parenthesis is optional.

(int a) -> {System.out.println("value "+a);};

The above can be rewritten as a -> {System.out.println("value "+a);};

6.8 We can assign a lambda to Functional Interface.

SummatiobInterface sumInt = (int a, int b) -> a+b;


7. Where to Use Lambda

You may have a question that where should we use Lambda Expression. For this, the Answer is "usage on any interface which has only one abstract method". In other words, on any Functional Interface.

Examples java API interfaces are Comparator, Runnable, Callable. All these interfaces are available in before java 8.

public interface Comparator {
 int compare(T o1, T o2);
}

public interface Runnable {
 void run();
}

public interface Callable {
 V call() throws Exception;
}

Many functional interfaces are introduced in Java 8 also. Predicate and Supplier are well known to developers.

7.1 Predicate:

Evaluates this predicate on the given argument. This takes type t as input and returns boolean.

@FunctionalInterface
public interface Predicate {
 boolean test (T t);
}

Predicate Example

Predicate p = (emp) -> emp.isCompleted5years();

7.2 Supplier:

Represents a supplier of results. This can hold any value.

@FunctionalInterface
public interface Supplier {

    T get();
}

Supplier Example

Supplier supplier = () -> "Java-W3schools";
String str = supplier.get();

The Supplier is getting string type and we can get the value by calling get() method of Supplier.

List of all functional interfaces in Java 12APIi

8. Lambda Sorting Example

Taking Employee class with id, salary, and designation fields. Now we want to sort the employees on salary.

Creating Employee class with constructor, setter and getter methods. And also overridden toString() method to print all the fields of Employee.

package com.java.w3schools.blog.streams.sorting;

public class Employee {

 private int id;
 private Long salary;
 private String designation;

 public Employee(int id, Long salary, String designation) {
  this.id = id;
  this.salary = salary;
  this.designation = designation;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public Long getSalary() {
  return salary;
 }

 public void setSalary(Long salary) {
  this.salary = salary;
 }

 public String getDesignation() {
  return designation;
 }

 public void setDesignation(String designation) {
  this.designation = designation;
 }

 @Override
 public String toString() {
  return "Employee [id=" + id + ", salary=" + salary + ", designation=" + designation + "]";
 }
}

Creating an Employee's array.

Employee[] employees = { new Employee(100, 10000L, "Software Engineer"), new Employee(101, 5000L, "Junior SE"),
    new Employee(105, 6000L, "Junior SE"), new Employee(110, 2500L, "Intern") };

Converting Employee array into List<Employee>.

List empList = Arrays.asList(employees);

8.1 Sorting Traditional Approach

First, we will write a program using traditional comparator object creation using an anonymous inner class.

Calling sort() method of List and passing an anonymous object for Comparator.

System.out.println("empList Before sorting : "+empList);
empList.sort(new Comparator() {
 @Override
 public int compare(Employee o1, Employee o2) {

  return o1.getSalary().compareTo(o2.getSalary());
 }
});

System.out.println("empList after sorting : "+empList);

Output:

empList Before sorting : [Employee [id=100, salary=10000, designation=Software Engineer], Employee [id=101, salary=5000, designation=Junior SE], Employee [id=105, salary=6000, designation=Junior SE], Employee [id=110, salary=2500, designation=Intern]]
empList after sorting : [Employee [id=110, salary=2500, designation=Intern], Employee [id=101, salary=5000, designation=Junior SE], Employee [id=105, salary=6000, designation=Junior SE], Employee [id=100, salary=10000, designation=Software Engineer]]

8.2 Sorting with Lambda

The above sorting code has lots of boiler plate code which is not required to write every time you sort.

See the below code with lambda which reduces the code and makes it clear to focus on sorting logic.

List lambdaEmpList = Arrays.asList(employees);

System.out.println("lambdaEmpList Before sorting : " + lambdaEmpList);
lambdaEmpList.sort((Employee o1, Employee o2) -> o1.getSalary().compareTo(o2.getSalary()));
System.out.println("lambdaEmpList after sorting : " + lambdaEmpList);

Output will be the same as the traditional approach but the coding effort is reduced.

sort() method takes two Employee parameters and compares the salary fields.

The same can be rewritten as below and works without any issues.

lambdaEmpList.sort((o1, o2) -> o1.getSalary().compareTo(o2.getSalary()));

Just removed the lambda parameters type because the compiler can infer the type from the underlying list. Here the list lambdaEmpList holds the Employee objects. So, the compiler can imply the type of Employee to o1 and o2.

9. Invalid Lambda Expressions

We've seen till now all valid lambda expressions. Now we'll see the invalid and what cases will get compile time errors.

Creating a interface with only one Abstract Method.

interface LambdaInt {
 public String convertIntToString(Integer value);
}

Writing the implementation for this interface using Lambda.

LambdaInt lambdaInt = (Integer value) -> return value.toString();

Here will get a compile time error.

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
 Syntax error on token "return", delete this token

Here, this lambda is returning String. This problem can be solved in two ways.

9.1 return with curly braces

if we write a statement with return "some value" statement then it must be enclosing in curly braces.

LambdaInt lambdaInt =  (Integer value) -> { return value.toString();};

9.2 remove return keyword

If the lambda body has only one statement and that is a value then no need to use the return keyword. And also no need of curly braces. Now, We can rewrite as below.

LambdaInt lambdaInt = (Integer value) -> value.toString();

9.3 Another Illegal Lambda

See the below Lambda which also give a compile error.

LambdaInt lambdaInt2 = (Integer value) -> {"String Value of ";};

compile error:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
 Syntax error, insert "AssignmentOperator Expression" to complete Expression


First, guess the problem before seeing the solution.

This is similar to the above problem that we solved.

To fix, We should add a return statement.

LambdaInt lambdaInt2 = (Integer value) -> {return "String Value of ";};

Or remove the curly braces and semicolon.

LambdaInt lambdaInt2 = (Integer value) -> "String Value of ";

10. Conclusion

In this article, We've seen What is Lambda Expression and how it is added to Java 8.

As well discussed all the following areas of Lambda's.

Comparing to Older Java Versions
Lambda Syntax
Lambda Valid Examples
Lambda Rules
Where to Use Lambda
Lambda Sorting Example
Invalid Lambda Expressions

All the code shown in this course are available over GitHub.

Next tutorial on Java 8 Stream introduction and Need of it.

No comments:

Post a Comment

Please do not add any spam links in the comments section.