What is a Lambda Expression in Java 8?
Lambda expressions are anonymous functions that enable functional programming in Java. They provide a clear and concise way to implement single-method interfaces (Functional Interfaces).
Basic Syntax
public class LambdaBasics {
public static void main(String[] args) {
// Traditional way (anonymous class)
Runnable oldWay = new Runnable() {
@Override
public void run() {
System.out.println("Hello from anonymous class");
}
};
// Lambda way (concise)
Runnable newWay = () -> System.out.println("Hello from lambda");
oldWay.run();
newWay.run();
// Lambda syntax variations:
// () -> expression
// () -> { statements; }
// (param) -> expression
// param -> expression (single param - parentheses optional)
// (param1, param2) -> expression
// (param1, param2) -> { statements; }
// Examples:
Runnable r1 = () -> System.out.println("No params");
Runnable r2 = () -> {
System.out.println("Multiple");
System.out.println("statements");
};
// Single parameter examples
java.util.function.Consumer c1 = (String s) -> System.out.println(s);
java.util.function.Consumer c2 = s -> System.out.println(s); // Type inferred
// Multiple parameters
java.util.function.BinaryOperator add = (a, b) -> a + b;
java.util.function.BinaryOperator multiply = (a, b) -> {
int result = a * b;
return result;
};
}
}
Lambda with Different Parameters
import java.util.function.*;
public class LambdaParameters {
public static void main(String[] args) {
// No parameters - Supplier
Supplier supplier = () -> "Hello from Supplier";
System.out.println(supplier.get());
// One parameter - Consumer
Consumer consumer = s -> System.out.println("Consumed: " + s);
consumer.accept("Java Lambda");
// One parameter with return - Function
Function strLength = (String s) -> s.length();
System.out.println("Length of 'Java': " + strLength.apply("Java"));
// Type inference (compiler determines type)
Function shorter = s -> s.length();
// Two parameters - BiFunction
BiFunction add = (a, b) -> a + b;
System.out.println("5 + 3 = " + add.apply(5, 3));
// Two parameters with same type - BinaryOperator
BinaryOperator multiply = (a, b) -> a * b;
System.out.println("5 * 3 = " + multiply.apply(5, 3));
// Predicate - returns boolean
Predicate isEven = n -> n % 2 == 0;
System.out.println("Is 10 even? " + isEven.test(10));
System.out.println("Is 7 even? " + isEven.test(7));
// Multiple statements
Function square = x -> {
int result = x * x;
System.out.println("Calculating square of " + x);
return result;
};
System.out.println("Square of 5: " + square.apply(5));
}
}
Common Functional Interfaces
import java.util.function.*;
import java.util.*;
public class FunctionalInterfaces {
public static void main(String[] args) {
// 1. Predicate - test(T t): boolean
Predicate isPositive = n -> n > 0;
Predicate isEven = n -> n % 2 == 0;
Predicate isNotEmpty = s -> !s.isEmpty();
System.out.println("Is 5 positive? " + isPositive.test(5));
System.out.println("Is 4 even? " + isEven.test(4));
// Predicate chaining
Predicate isPositiveAndEven = isPositive.and(isEven);
System.out.println("Is 5 positive and even? " + isPositiveAndEven.test(5));
System.out.println("Is 4 positive and even? " + isPositiveAndEven.test(4));
// 2. Function - apply(T): R
Function toLength = String::length;
Function doubleIt = n -> n * 2;
Function lengthThenDouble = toLength.andThen(doubleIt);
System.out.println("Double length of 'Java': " + lengthThenDouble.apply("Java"));
// 3. Consumer - accept(T): void
Consumer printer = System.out::println;
Consumer logger = s -> System.out.println("LOG: " + s);
Consumer combined = printer.andThen(logger);
combined.accept("Hello World");
// 4. Supplier - get(): T
Supplier random = Math::random;
Supplier greeting = () -> "Hello from Supplier";
System.out.println("Random: " + random.get());
System.out.println(greeting.get());
// 5. UnaryOperator - apply(T): T (extends Function)
UnaryOperator increment = x -> x + 1;
UnaryOperator toUpper = String::toUpperCase;
System.out.println("Increment 10: " + increment.apply(10));
System.out.println("Upper 'java': " + toUpper.apply("java"));
// 6. BinaryOperator - apply(T,T): T (extends BiFunction)
BinaryOperator max = Integer::max;
BinaryOperator concat = (s1, s2) -> s1 + s2;
System.out.println("Max of 10, 20: " + max.apply(10, 20));
System.out.println("Concat 'Hello', 'World': " + concat.apply("Hello", "World"));
// 7. BiFunction - apply(T,U): R
BiFunction repeat = (s, n) -> s.repeat(n);
System.out.println("Repeat 'Hi' 3 times: " + repeat.apply("Hi", 3));
}
}
Lambda with Collections
public class LambdaCollections {
public static void main(String[] args) {
List names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
System.out.println("Original list: " + names);
// Sort with lambda
names.sort((s1, s2) -> s1.compareTo(s2));
System.out.println("Sorted A-Z: " + names);
// Sort descending
names.sort((s1, s2) -> s2.compareTo(s1));
System.out.println("Sorted Z-A: " + names);
// Sort by length
names.sort((s1, s2) -> Integer.compare(s1.length(), s2.length()));
System.out.println("Sorted by length: " + names);
// Iterate with forEach
System.out.println("
Iterating with forEach:");
names.forEach(name -> System.out.println(" " + name));
// Filter and collect
List longNames = names.stream()
.filter(name -> name.length() > 4)
.collect(Collectors.toList());
System.out.println("
Names with length > 4: " + longNames);
// Remove if condition
names.removeIf(name -> name.startsWith("A"));
System.out.println("After removing names starting with A: " + names);
// Replace all
names.replaceAll(name -> name.toUpperCase());
System.out.println("After toUpperCase: " + names);
// Map operation with lambda
List nameLengths = names.stream()
.map(name -> name.length())
.collect(Collectors.toList());
System.out.println("Name lengths: " + nameLengths);
// Reduce operation
String concatenated = names.stream()
.reduce("", (acc, name) -> acc + name + ", ");
System.out.println("Concatenated: " + concatenated);
}
}
Custom Functional Interface
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
// Only one abstract method allowed
// default and static methods allowed
default void printResult(int result) {
System.out.println("Result: " + result);
}
static void info() {
System.out.println("Calculator Interface - Functional Interface Demo");
}
}
// Another custom functional interface
@FunctionalInterface
interface StringTransformer {
String transform(String input);
default String transformAndPrint(String input) {
String result = transform(input);
System.out.println("Transformed: '" + input + "' -> '" + result + "'");
return result;
}
}
public class CustomFunctionalInterface {
public static void main(String[] args) {
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;
Calculator subtract = (a, b) -> a - b;
Calculator divide = (a, b) -> {
if (b != 0) return a / b;
return 0;
};
Calculator.info();
System.out.println("Add: " + add.calculate(10, 5));
System.out.println("Multiply: " + multiply.calculate(10, 5));
System.out.println("Subtract: " + subtract.calculate(10, 5));
System.out.println("Divide: " + divide.calculate(10, 5));
add.printResult(add.calculate(10, 5));
// StringTransformer examples
StringTransformer toUpper = s -> s.toUpperCase();
StringTransformer reverse = s -> new StringBuilder(s).reverse().toString();
StringTransformer addExclamation = s -> s + "!!!";
toUpper.transformAndPrint("hello");
reverse.transformAndPrint("hello");
addExclamation.transformAndPrint("hello");
// Chaining transformations
StringTransformer combined = s -> addExclamation.transform(reverse.transform(toUpper.transform(s)));
System.out.println("Chained: " + combined.transform("hello"));
}
}
Variable Capture (Effectively Final)
public class VariableCapture {
private static int staticVar = 100;
private int instanceVar = 200;
public void demonstrateCapture() {
int localVar = 300; // effectively final (not modified after initialization)
// Lambda can capture static, instance, and local variables
Runnable r = () -> {
System.out.println("Static variable: " + staticVar);
System.out.println("Instance variable: " + instanceVar);
System.out.println("Local variable: " + localVar);
// Cannot modify local variable
// localVar = 400; // ERROR - must be effectively final
// Can modify instance and static variables
instanceVar++;
staticVar++;
};
r.run();
System.out.println("After lambda - instanceVar: " + instanceVar);
System.out.println("After lambda - staticVar: " + staticVar);
// localVar cannot be modified after lambda
// localVar = 301; // Would cause error if lambda uses it
}
public static void main(String[] args) {
new VariableCapture().demonstrateCapture();
// Capturing with loop variable (not effectively final)
List runnables = new ArrayList<>();
for (int i = 0; i < 5; i++) {
final int captured = i; // Need final or effectively final
runnables.add(() -> System.out.println("Value: " + captured));
}
runnables.forEach(Runnable::run);
}
}
Method References (Lambda Shortcuts)
import java.util.stream.*;
public class MethodReferences {
public static void main(String[] args) {
List words = Arrays.asList("Java", "Lambda", "Stream", "Method", "Reference");
System.out.println("=== 4 Types of Method References ===
");
// 1. Static method reference: Class::staticMethod
System.out.println("1. Static method reference:");
words.stream()
.map(Integer::parseInt) // Won't work for strings, just syntax example
.forEach(System.out::println);
// Actual working example:
List numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.map(Math::sqrt) // Static method reference
.forEach(System.out::println);
// 2. Instance method of arbitrary object: Class::instanceMethod
System.out.println("
2. Instance method of arbitrary object:");
words.stream()
.map(String::toUpperCase) // Reference to instance method
.forEach(System.out::println);
words.stream()
.map(String::length) // Instance method with return
.forEach(System.out::println);
// 3. Instance method of specific object: object::instanceMethod
System.out.println("
3. Instance method of specific object:");
Printer printer = new Printer();
words.forEach(printer::print); // Specific object reference
// 4. Constructor reference: Class::new
System.out.println("
4. Constructor reference:");
Supplier> listSupplier = ArrayList::new;
List newList = listSupplier.get();
newList.add("Created via constructor reference");
System.out.println(newList);
// Constructor reference with array
Function arrayCreator = String[]::new;
String[] array = arrayCreator.apply(5);
System.out.println("Array length: " + array.length);
// Constructor reference with custom class
Supplier sbSupplier = StringBuilder::new;
StringBuilder sb = sbSupplier.get();
sb.append("Hello from constructor reference");
System.out.println(sb);
}
}
class Printer {
void print(String s) {
System.out.println("Printing: " + s);
}
}
// Custom class for constructor reference
class Person {
String name;
Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{name='" + name + "'}";
}
}
Master Java 8 Lambda expressions with Online Learner!
0
likes
Your Feedback
Help us improve by sharing your thoughts
Online Learner helps developers master programming, database concepts, interview preparation, and real-world implementation through structured learning paths.
Quick Links
© 2023 - 2026 OnlineLearner.in | All Rights Reserved.
