Java Streams have become an essential part of modern Java programming. Introduced in Java 8, Streams provide a powerful way to process sequences of elements in a functional style. They simplify operations on collections, arrays, or data sources, enabling cleaner and more readable code. This guide covers everything you need to know about Stream in Java, from basics to advanced use cases.
A Stream in Java is a sequence of elements supporting functional-style operations on data. Unlike collections, streams do not store elements; instead, they compute results on demand.
Java Streams, introduced in Java 8, provide a modern way to process sequences of elements using a functional approach. Streams make working with collections, arrays, and other data sources concise and readable. This guide explains Java Streams for beginners and intermediate learners with practical examples and real-world use cases.
A Stream in Java is a sequence of elements that supports functional-style operations. Unlike collections, streams do not store data; they process it on demand.
import java.util.*; import java.util.stream.*; Listnames = Arrays.asList("Alice", "Bob", "Charlie"); Stream nameStream = names.stream(); nameStream.forEach(System.out::println);
String[] fruits = {"Apple", "Banana", "Cherry"}; StreamfruitStream = Arrays.stream(fruits); fruitStream.forEach(System.out::println);
Streamnumbers = Stream.of(1, 2, 3, 4, 5); numbers.forEach(System.out::println);
Listnumbers = Arrays.asList(1, 2, 3, 4, 5); List evenNumbers = numbers.stream() .filter(n -> n % 2 == 0) .collect(Collectors.toList()); System.out.println(evenNumbers);
Listnames = Arrays.asList("Alice", "Bob"); List nameLengths = names.stream() .map(String::length) .collect(Collectors.toList()); System.out.println(nameLengths);
Listnumbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream() .reduce(0, Integer::sum); System.out.println("Sum: " + sum);
Listnames = Arrays.asList("Charlie", "Alice", "Bob"); List sortedNames = names.stream() .sorted() .collect(Collectors.toList()); System.out.println(sortedNames);
Listnumbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5); List uniqueNumbers = numbers.stream() .distinct() .collect(Collectors.toList()); System.out.println(uniqueNumbers);
Listnumbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); int sum = numbers.parallelStream() .mapToInt(Integer::intValue) .sum(); System.out.println("Parallel Sum: " + sum);
Note: Use parallel streams cautiously. They are most beneficial for CPU-intensive operations and large datasets.
class Employee { String name; int age; Employee(String name, int age) { this.name = name; this.age = age; } } Listemployees = Arrays.asList( new Employee("Alice", 30), new Employee("Bob", 22), new Employee("Charlie", 28) ); List filteredEmployees = employees.stream() .filter(emp -> emp.age > 25) .collect(Collectors.toList()); filteredEmployees.forEach(emp -> System.out.println(emp.name));
These operations return a new stream and are lazy. Examples include:
filter() – filters elements based on a predicate
map() – transforms elements
distinct() – removes duplicates
sorted() – sorts elements
These operations produce a result or side effect and trigger processing of the stream. Examples include:
forEach() – performs an action for each element
collect() – gathers elements into a collection
reduce() – reduces elements to a single value
count() – counts elements
import java.util.*; import java.util.stream.*; public class StreamExample { public static void main(String[] args) { Listnames = Arrays.asList("Alice", "Bob", "Charlie", "David"); Stream nameStream = names.stream(); nameStream.forEach(System.out::println); } }
import java.util.*; import java.util.stream.*; public class ArrayStreamExample { public static void main(String[] args) { String[] fruits = {"Apple", "Banana", "Cherry"}; StreamfruitStream = Arrays.stream(fruits); fruitStream.forEach(System.out::println); } }
import java.util.stream.*; public class StreamOfExample { public static void main(String[] args) { Streamnumbers = Stream.of(1, 2, 3, 4, 5); numbers.forEach(System.out::println); } }
Listnumbers = Arrays.asList(1, 2, 3, 4, 5, 6); List evenNumbers = numbers.stream() .filter(n -> n % 2 == 0) .collect(Collectors.toList()); System.out.println(evenNumbers);
Listnames = Arrays.asList("Alice", "Bob"); List nameLengths = names.stream() .map(String::length) .collect(Collectors.toList()); System.out.println(nameLengths);
Listnumbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream() .reduce(0, (a, b) -> a + b); System.out.println("Sum: " + sum);
Listnames = Arrays.asList("Charlie", "Alice", "Bob"); List sortedNames = names.stream() .sorted() .collect(Collectors.toList()); System.out.println(sortedNames);
Listnumbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5); List uniqueNumbers = numbers.stream() .distinct() .collect(Collectors.toList()); System.out.println(uniqueNumbers);
class Employee { String name; int age; Employee(String name, int age) { this.name = name; this.age = age; } } Listemployees = Arrays.asList( new Employee("Alice", 30), new Employee("Bob", 22), new Employee("Charlie", 28) ); List filteredEmployees = employees.stream() .filter(emp -> emp.age > 25) .collect(Collectors.toList()); filteredEmployees.forEach(emp -> System.out.println(emp.name));
Listnumbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); int sum = numbers.parallelStream() .mapToInt(Integer::intValue) .sum(); System.out.println("Parallel Sum: " + sum);
Note: Parallel streams are not always faster. Use them carefully for CPU-intensive tasks.
Streams in Java provide a modern, functional approach to handling collections and sequences of data. By using intermediate and terminal operations, developers can write more concise, readable, and efficient code. Streams are ideal for filtering, transforming, aggregating, and processing data both sequentially and in parallel. Understanding Streams is essential for any Java developer seeking to write clean and performant applications.
Collections store data, while Streams process data without storing it. Streams are used for functional-style operations, while collections focus on storage and retrieval.
No. Once a terminal operation is executed, the stream is consumed and cannot be reused. You must create a new stream for further operations.
Intermediate operations return a new stream and are lazy, such as map(), filter(), and distinct(). They are executed only when a terminal operation is invoked.
Use parallelStream() on a collection to process elements in parallel. Example: collection.parallelStream().forEach(System.out::println);
Avoid Streams for simple loops with minimal processing, where overhead may outweigh benefits. Also, avoid parallel streams when thread-safety or order matters.
Java Streams provide a modern, functional approach to processing collections and sequences of data. By using streams, developers can write cleaner, more readable, and efficient code with operations like map, filter, reduce, and collect. Streams also support parallel processing, making it easier to handle large datasets efficiently. Understanding streams is essential for writing modern Java applications that are both performant and maintainable.
Copyrights © 2024 letsupdateskills All rights reserved