Java 8 - Lambda Expressions
Bài đăng này đã không được cập nhật trong 7 năm
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
All rights reserved