`
Streams and Lambda expressions are key features introduced in Java 8 that make Java programming more functional and concise, especially when dealing with collections and bulk data operations.
A Stream in Java is a sequence of elements that can be processed in parallel or sequentially. Streams allow operations like filtering, mapping, and reducing on collections of data without altering the original data.
filter()
, map()
, and reduce()
allow functional programming.These return another Stream
and are lazy (executed only when a terminal operation is called).
filter(Predicate)
: Filters elements based on a condition.map(Function)
: Transforms elements to another form.sorted()
: Sorts the elements.distinct()
: Removes duplicates.limit(n)
: Truncates the stream to the first n
elements.skip(n)
: Skips the first n
elements.These trigger the execution of the stream pipeline.
forEach(Consumer)
: Iterates over each element.collect(Collectors)
: Converts the stream into a collection or value.reduce(BinaryOperator)
: Aggregates elements into a single value.count()
: Returns the number of elements.findFirst()
/ findAny()
: Returns an optional containing the first/any element.allMatch()
/ anyMatch()
/ noneMatch()
: Tests elements against a predicate.import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Tom", "Tim");
// Filter names starting with 'T' and convert them to uppercase
List<String> result = names.stream()
.filter(name -> name.startsWith("T"))
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(result); // Output: [TOM, TIM]
}
}
import java.util.Arrays;
import java.util.List;
public class ReduceExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// Sum of all numbers
int sum = numbers.stream()
.reduce(0, Integer::sum);
System.out.println("Sum: " + sum); // Output: Sum: 15
}
}
A Lambda Expression is a concise way to represent an anonymous function. It enables functional programming by treating functions as first-class citizens.
(parameters) -> expression
(parameters) -> {
// multiple statements
}
A functional interface is an interface with a single abstract method (SAM). Some examples include:
Runnable
Callable
Comparator
Consumer
, Function
, Predicate
, Supplier
(from java.util.function
).import java.util.Arrays;
import java.util.List;
public class LambdaComparator {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Tom", "Tim");
// Sort names in reverse order using Lambda
names.sort((a, b) -> b.compareTo(a));
System.out.println(names); // Output: [Tom, Tim, John, Jane]
}
}
Predicate
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// Predicate to check if a number is even
Predicate<Integer> isEven = n -> n % 2 == 0;
numbers.stream()
.filter(isEven)
.forEach(System.out::println); // Output: 2 4
}
}
The real power of streams is unlocked with lambda expressions, allowing concise and functional-style operations.
import java.util.Arrays;
import java.util.List;
public class StreamLambdaExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// Find the sum of squares of even numbers
int sumOfSquares = numbers.stream()
.filter(n -> n % 2 == 0) // Filter even numbers
.map(n -> n * n) // Square each number
.reduce(0, Integer::sum); // Sum them up
System.out.println("Sum of squares: " + sumOfSquares); // Output: 20
}
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class GroupingExample {
public static void main(String[] args) {
List<String> items = Arrays.asList("apple", "banana", "cherry", "apple", "banana", "cherry", "cherry");
// Group items by their frequency
Map<String, Long> frequency = items.stream()
.collect(Collectors.groupingBy(item -> item, Collectors.counting()));
System.out.println(frequency); // Output: {banana=2, cherry=3, apple=2}
}
}
parallelStream()
.You can process streams in parallel using parallelStream()
, which divides tasks into multiple threads.
import java.util.Arrays;
import java.util.List;
public class ParallelStreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.parallelStream()
.forEach(n -> System.out.println(Thread.currentThread().getName() + ": " + n));
}
}