12/08/2018, 15:52

Java 8 - Lambda Expressions

Definition of Lambda A formal system for expressing computational behaviour. Invented by Alonzo Church in 1930. Lambda expressions consist of many parentheses i.e in Y-Combinator: Y = λf .(λx.f (xx))(λx.f (xx)) 3 / 19 The Idea, behind Functions are first-class ...

Definition of Lambda

  • A formal system for expressing computational behaviour.
    • Invented by Alonzo Church in 1930.
  • Lambda expressions consist of many parentheses i.e in Y-Combinator:
Y = λf .(λx.f (xx))(λx.f (xx)) 3 / 19

The Idea, behind

  • Functions are first-class citizens.
  • Lambda expressions are high order functions:
    • They take other functions as a parameter.
    • They may return functions.
  • The functions in Lambda all referentially transparent (pure functions). They:
    • provide a better parallelisation (no side-effects),
    • are easier to test,
    • are cacheable and provide lazy evaluation.

Functional Programming with Java 8

In computer science, functional programming is a programming paradigm, a style of building the structure and elements of computer programs, that treats computation as the evaluation of mathematical functions and avoids changing state and mutable data. It is a declarative programming paradigm, which means programming is done with expressions.

Why Functional?

  • Less code
  • Expressive code
  • Correct code
  • It is FUN
  • Performance

Functional building blocks in java 8

  • Function
  • Function reference
  • Lambda
  • Predefined Java8 functions - java.util.function
  • Stream API p2

Java 8 - Lambda Expressions

  • Lambda expressions are introduced in Java 8 and are touted to be the biggest feature of Java 8. Lambda expression facilitates functional programming, and simplifies the development a lot.
  • Allow Java expressions or blocks to be treated as objects.

History

  • First planned for inclusion in Java SE 7
    • Java SE 7 was released almost 5 years after Java SE 6
    • Java SE 7 did not include lambda expressions
  • Was in jeopardy of not making it into Java SE 8
    • Decision was made to delay Java SE 8 until March 2014
    • Lambda expressions are too important to defer again
  • Included in Java SE 8
    • Feature complete
    • GA is planned for March 2014

Lambda Expressions Syntax

Syntax:

(parameter-list) -> expression | { statements }

Returned value is either expression or the value returned from the statements block The type of the lambda expression is inferred based on the returned value; void if the expression or block is void.

Special case for a single parameter:

parameter -> expression | { statements }

Important characteristics of a lambda expression

Optional type declaration: No need to declare the type of a parameter. The compiler can inference the same from the value of the parameter. MathOperation subtraction = (a, b) -> a - b; Optional parenthesis around parameter: No need to declare a single parameter in parenthesis. For multiple parameters, parentheses are required. GreetingService greetService1 = message -> System.out.println("Hello " + message); Optional curly braces: No need to use curly braces in expression body if the body contains a single statement. MathOperation division = (int a, int b) -> a / b; Optional return keyword: The compiler automatically returns the value if the body has a single expression to return the value. Curly braces are required to indicate that expression returns a value. MathOperation multiplication = (int a, int b) -> { return a * b; };

Lambda Expressions Example

Public class Tester {
    public static void main(String args[]) {
    Tester tester = new Tester();
        SumOperation addition = (n1, n2) -> n1 + n2;			
        System.out.println("addition: " + tester.operate(2, 3, addition));
    }

    interface SumOperation {
    int operation(int n1, int n2);
    }

    private int operate(int n1, int n2, SumOperation sumOperation){
    return sumOperation.operation(n1, n2);
    }
}

Lambda Expressions Example

  • Lambda expressions are used primarily to define inline implementation of a functional interface, i.e., an interface with a single method only. In the above example, we've used lambda expressions to define the operation method of SumOperation interface.
  • Lambda expression eliminates the need of anonymous class and gives a very simple yet powerful functional programming capability to Java.

Lambda Expressions Scope

  • Lexically scoped
    • this is the scope in which the lambda expression is defined, not some generated anonymous inner class
  • Can refer to local variables
    • Just like anonymous inner classes
    • Local variables need only be “effectively” final, i.e., not assigned after the lambda expression is created
    • Local variables are said to be “captured”, which requires a new lambda to be created each time
    • Non-capturing lambda expressions require only a single instance

Scope Example

public class Tester {
    // "compares" belongs to "this" object
	int compares;
	public static void main(String args[]) {
		Tester tester = new Tester();
		System.out.println(tester.isPreferredPet("cat"));
   	}
	
	boolean isPreferredPet(String pet) {
	 	// pet is "effectively final"
		
	   	return Stream.of("dog", "cat", "fish").
	      		peek( a -> compares++ ).
	      		anyMatch( a -> a.equals(pet) ) ;
	}
}

Delegating Lambda Expressions

  • Many lambda expressions simply delegate to a single method
names.forEach(s -> System.out.println(s));
  • Possible to create a constant to do this
static final Consumer PRINT =
        s -> System.out.println(s);
names.forEach(PRINT);

Method References

Simplified thanks to method references

names.forEach(System.out::println);

Or even

static final Consumer PRINT =
        System.out::println;
names.forEach(PRINT);

Exceptions in Lambda Expressions

Consumer boom = s -> s.notify();
boom.accept(null);
Exception in thread "main" java.lang.NullPointerException
    at com.eg.Main.lambda$0(Main.java:5)
    at com.eg.Main$$Lambda$1.accept(Unknown Source)
    at com.eg.Main.main(Main.java:7)

Limitations of Lambda Expressions

  • Cannot break or continue outside of the lambda expression
  • Cannot access non-effectively-final local variables
  • Cannot implement abstract classes, even single abstract method (SAM) abstract classes
  • Exceptions in a lambda expression are handled as per anonymous inner classes
    • If the functional interface throws the exception, then fine
    • Otherwise, a bit of a pain if any other checked exception
0