Streams and Lambda Expressions
Lambda expressions
List<String> courses = List.of("Python", "Java", "SQL");
courses.forEach(course -> System.out.println(course));
A lambda is a compact, anonymous function — course -> System.out.println(course) is shorthand for a one-method class implementing a functional interface, without the boilerplate that would have required in older Java. This is the same idea as JavaScript’s arrow functions and Python’s lambda, applied to a statically typed language.
The Streams API
List<String> longNames = courses.stream()
.filter(c -> c.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toList());
long count = courses.stream().filter(c -> c.startsWith("J")).count();
Streams let you chain filter, map, and collect to transform a collection declaratively — describing what transformation you want rather than writing the loop yourself. This is the exact same idea as JavaScript’s filter/map, and Python’s list comprehensions, expressed through Java’s type system.
Method references
String::toUpperCase above is a method reference — shorthand for the lambda s -> s.toUpperCase(), used whenever a lambda would do nothing but call one existing method on its argument. It’s purely a readability shortcut; both forms compile to the same thing.
Common stream operations
Optional<String> first = courses.stream().findFirst();
boolean anyMatch = courses.stream().anyMatch(c -> c.equals("Java"));
List<String> sorted = courses.stream().sorted().collect(Collectors.toList());
Optional is Java’s way of representing “a value that might not exist” without resorting to null and the null-pointer bugs that come with it — a stream operation like findFirst() that might legitimately find nothing returns an Optional rather than risking a null.