`
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:
RunnableCallableComparatorConsumer, 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]
}
}
Predicateimport 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));
}
}