Lecture 10
Lambda expressions, functional interfaces, method references, and Stream API
This work is licensed under CC BY-NC-SA 4.0
© Way-Up 2025
import java.util.Arrays;
import java.util.List;
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Old way: using anonymous class
names.forEach(new Consumer<String>() {
@Override
public void accept(String name) {
System.out.println(name);
}
});
import java.util.Arrays;
import java.util.List;
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// New way: using lambda expression
names.forEach(name -> System.out.println(name));
// Even shorter with method reference
names.forEach(System.out::println);
// Basic syntax: (parameters) -> expression
(x, y) -> x + y
// With type declarations
(int x, int y) -> x + y
// Single parameter (parentheses optional)
x -> x * 2
// No parameters
() -> System.out.println("Hello")
// Multiple statements (need curly braces)
(x, y) -> {
int sum = x + y;
return sum * 2;
}
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}
// Using the functional interface with a lambda
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;
System.out.println(add.calculate(5, 3)); // 8
System.out.println(multiply.calculate(5, 3)); // 15
@FunctionalInterface annotation is optional but recommendedjava.util.function:Predicate<Integer> isPositive = x -> x > 0;
Function<String, Integer> length = s -> s.length();
Consumer<String> print = s -> System.out.println(s);
Supplier<Double> random = () -> Math.random();
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
// Define predicates
Predicate<Integer> isEven = x -> x % 2 == 0;
Predicate<Integer> isPositive = x -> x > 0;
// Test values
System.out.println(isEven.test(4)); // true
System.out.println(isPositive.test(-5)); // false
// Combine predicates
Predicate<Integer> isPositiveEven = isEven.and(isPositive);
System.out.println(isPositiveEven.test(4)); // true
System.out.println(isPositiveEven.test(-4)); // false
}
}
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
// Define functions
Function<String, Integer> length = s -> s.length();
Function<Integer, Integer> square = x -> x * x;
// Apply functions
System.out.println(length.apply("Hello")); // 5
System.out.println(square.apply(4)); // 16
// Chain functions
Function<String, Integer> lengthSquared = length.andThen(square);
System.out.println(lengthSquared.apply("Hi")); // 4 (length=2, square=4)
}
}
import java.util.Arrays;
import java.util.List;
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Lambda expression
names.forEach(name -> System.out.println(name));
// Method reference (equivalent)
names.forEach(System.out::println);
// Static method reference
Function<String, Integer> parseInt = Integer::parseInt;
// Instance method reference
String str = "Hello";
Supplier<Integer> lengthSupplier = str::length;
// Constructor reference
Supplier<List<String>> listSupplier = ArrayList::new;
import java.util.Arrays;
import java.util.List;
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// Create a stream and perform operations
numbers.stream()
.filter(n -> n % 2 == 0) // Intermediate: keep even numbers
.map(n -> n * 2) // Intermediate: double each number
.forEach(System.out::println); // Terminal: print results
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
// Filter names starting with 'A' or 'C'
List<String> filtered = names.stream()
.filter(name -> name.startsWith("A") || name.startsWith("C"))
.collect(Collectors.toList());
System.out.println(filtered); // [Alice, Charlie]
// Filter numbers greater than 50
List<Integer> numbers = Arrays.asList(10, 45, 60, 75, 30, 90);
List<Integer> large = numbers.stream()
.filter(n -> n > 50)
.collect(Collectors.toList());
System.out.println(large); // [60, 75, 90]
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
List<String> names = Arrays.asList("alice", "bob", "charlie");
// Convert to uppercase
List<String> uppercase = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(uppercase); // [ALICE, BOB, CHARLIE]
// Get string lengths
List<Integer> lengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println(lengths); // [5, 3, 7]
import java.util.Arrays;
import java.util.List;
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// Sum all numbers
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
System.out.println("Sum: " + sum); // 15
// Find maximum
int max = numbers.stream()
.reduce(Integer.MIN_VALUE, (a, b) -> a > b ? a : b);
System.out.println("Max: " + max); // 5
// Using method reference for sum
int sum2 = numbers.stream()
.reduce(0, Integer::sum);
System.out.println("Sum2: " + sum2); // 15
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Alice");
// Collect to List
List<String> list = names.stream()
.collect(Collectors.toList());
// Collect to Set (removes duplicates)
Set<String> set = names.stream()
.collect(Collectors.toSet());
// Join strings
String joined = names.stream()
.collect(Collectors.joining(", "));
System.out.println(joined); // Alice, Bob, Charlie, Alice
class Employee {
private String name;
private int age;
private double salary;
// Constructor, getters, setters...
}
List<Employee> employees = Arrays.asList(
new Employee("Alice", 25, 50000),
new Employee("Bob", 35, 75000),
new Employee("Charlie", 28, 60000)
);
// Find employees earning more than 55000
List<String> highEarners = employees.stream()
.filter(e -> e.getSalary() > 55000)
.map(Employee::getName)
.collect(Collectors.toList());
System.out.println(highEarners); // [Bob, Charlie]
stream(), filter(), map(), and collect()List<String> words = Arrays.asList("apple", "banana", "cat",
"dog", "elephant", "fish");
// Expected output: "BANANA | ELEPHANT"
[19.99, 25.50, 15.00, 42.00, 8.99]reduce(), filter(), count(), and max()Student class with name and grade fields. Then:class Student {
String name;
int grade;
// Constructor, getters...
}
class Transaction {
String id;
String type; // "CREDIT" or "DEBIT"
double amount;
LocalDate date;
}