Lambda expressions let you define "anonymous methods" that are concise and can be passed as arguments. They align well with functional programming paradigms.
This guide walks you through lambda expressions in Java, covering their purpose, syntax, advantages, and use cases.
Key Takeaways
- Lambda expressions provide a concise syntax to implement functional interfaces.
- They streamline working with collections and enable method references.
- Use lambda expressions for cleaner, more expressive code.
What are Lambdas in Java?
Lambdas allow you to implement functional interfaces more concisely, as shown here:
interface Print {
void print(String message);
}
public class MainClass {
public static void main(String[] args) {
Print myPrinter = x -> System.out.println(x);
myPrinter.print("Hello lambdas!");
}
}
In this example, Print is a functional interface with one abstract method. The lambda expression x -> System.out.println(x) implements this method succinctly.
Passable as Function Arguments
Lambdas can be passed as arguments to functions. Here's an example with a math operation:
interface MathOp {
int operate(int a, int b);
}
public class MainClass {
public static void printResults(int x) {
System.out.println(x);
}
public static void main(String[] args) {
MathOp add = (a, b) -> a + b;
printResults(add.operate(2, 2)); //prints 4
}
}
The lambda add implements the MathOp interface, showing how lambdas can simplify code.
Lambda Syntax
A lambda in Java consists of:
1) Argument List
This is a comma-separated list of parameters, like (a, b). Types are inferred.
2) Arrow Token
The arrow token -> separates parameters from the body.
3) Body
The body is the implementation. For single expressions, you can omit curly braces and return.
Why Use Lambdas in Java?
Concise Syntax
Lambdas reduce boilerplate compared to anonymous classes. Here's a comparison:
interface Print {
void print(String message);
}
public class MainClass {
public static void main(String[] args) {
Print myNestedPrinter = new Print() {
public void print(String x) {
System.out.println(x);
}
};
Print myPrinter = x -> System.out.println(x);
myNestedPrinter.print("Hello nested classes");
myPrinter.print("Hello lambdas!");
}
}
You can see that using lambdas shorten the code and improve readability.
Ease with Collections
Using lambdas with collections is elegant, notably with the Streams API:
import java.util.*;
public class MainClass {
public static void main(String[] args) {
List list = Arrays.asList('a', 'b', 'c');
list.forEach(x -> System.out.println(x));
}
}
The example above uses forEach with a lambda for concise iteration.
Method References
Use method references when a lambda directly calls an existing method.
interface Print {
void print(String msg);
}
public class MainClass {
public static void systemPrint(String x) {
System.out.println(x);
}
public static void main(String[] args) {
Print methodPrint = MainClass::systemPrint;
methodPrint.print("Method reference");
}
}
Here, MainClass::systemPrint is a method reference, replacing a lambda expression.
The java.util.function Package
The java.util.function package offers ready-to-use functional interfaces.
import java.util.function.Consumer;
public class MainClass {
public static void main(String[] args) {
Consumer myConsumer = x -> System.out.println(x);
myConsumer.accept("Hello world!");
}
}
The Consumer is a generic interface, perfect for actions on single arguments.
Lambda Scope and Lexical Scoping
Lambdas are lexically scoped, meaning they capture variables as they are in their surrounding context, provided the variables are effectively final:
interface Print {
void print();
}
public class MainClass {
public static void main(String[] args) {
String message = "Hello world!";
Print myPrinter = () -> {
System.out.println(message);
};
myPrinter.print();
}
}
Here, message is final, accessible from within the lambda.
Conclusion
Java's support for lambda expressions enhances a functional programming approach, making code concise and expressive. Dive deeper into lambdas through resources like Dhruv Rai Puri's explanation of internal vs. external iterators or Esteban Herrera's article on method references.
FAQ
What is a functional interface?
A functional interface is an interface with only one abstract method, suitable for lambda expressions.
Can lambdas have multiple statements?
Yes, for multiple statements use curly braces and explicit returns in the lambda body.
What is the main benefit of using lambdas?
Lambdas make code more readable and concise, especially for implementing single-method interfaces.
How are lambdas different from anonymous classes?
Unlike anonymous classes, lambdas are lighter and don't retain a lexical scope, making them easier to use for functional programming.
