For working professionals
For fresh graduates
More
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
Foreign Nationals
The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not .
6. JDK in Java
7. C++ Vs Java
16. Java If-else
18. Loops in Java
20. For Loop in Java
46. Packages in Java
53. Java Collection
56. Generics In Java
57. Java Interfaces
60. Streams in Java
63. Thread in Java
67. Deadlock in Java
74. Applet in Java
75. Java Swing
76. Java Frameworks
78. JUnit Testing
81. Jar file in Java
82. Java Clean Code
86. Java 8 features
87. String in Java
93. HashMap in Java
98. Enum in Java
101. Hashcode in Java
105. Linked List in Java
109. Array Length in Java
111. Split in java
112. Map In Java
115. HashSet in Java
118. DateFormat in Java
121. Java List Size
122. Java APIs
128. Identifiers in Java
130. Set in Java
132. Try Catch in Java
133. Bubble Sort in Java
135. Queue in Java
142. Jagged Array in Java
144. Java String Format
145. Replace in Java
146. charAt() in Java
147. CompareTo in Java
151. parseInt in Java
153. Abstraction in Java
154. String Input in Java
156. instanceof in Java
157. Math Floor in Java
158. Selection Sort Java
159. int to char in Java
164. Deque in Java
172. Trim in Java
173. RxJava
174. Recursion in Java
175. HashSet Java
177. Square Root in Java
190. Javafx
Streams in Java were introduced in Java 8 to simplify data processing. A stream represents a sequence of objects that can be processed in a functional style. Unlike collections, streams do not store data but provide methods to perform operations such as filtering, mapping, and reducing. This allows developers to work with large datasets more efficiently and with cleaner code.
This tutorial on Streams in Java covers the key concepts, operations, and methods of the Stream API. You will learn about intermediate and terminal operations, features of streams, and practical examples with code snippets. The blog is designed to help learners understand how to use Java Streams effectively for building robust and maintainable applications.
Advance your Java programming expertise with our Software Engineering courses and elevate your learning to the next level.
Streams in Java are a feature introduced in Java 8 that allow developers to process collections of data in a functional and declarative manner. A stream represents a sequence of elements that can be transformed, filtered, or reduced using various operations.
Accelerate your tech career by mastering future-ready skills in Cloud, DevOps, AI, and Full Stack Development. Gain hands-on experience, learn from industry leaders, and develop the expertise that top employers demand.
Unlike collections, streams do not store data; they work on data sources such as lists, arrays, or I/O channels. Streams in Java support method chaining, lazy evaluation, and parallel processing, making them powerful for handling large datasets efficiently while keeping code clean, concise, and easy to maintain.
Intermediate operations are operations that change one stream into another stream. These operations are called "intermediate" because they do not produce a final result or a terminal operation but instead return a new stream that can be further operated upon. The following are a few common intermediate operations in Java Streams:
Must Read: Top 13 String Functions in Java
Terminal operations in Java streams are those operations that initiate the processing of the stream elements and return a non-stream result. Here are explanations for three common terminal operations:
Here is a program to demonstrate the use of Stream with the stream() method:
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().mapToInt(Integer::intValue).sum();
System.out.println("Sum: " + sum);
}
}
In this program, we have a list of integers called numbers that contains the values 1, 2, 3, 4, and 5.
We use the Stream API to create a stream from the numbers list by calling the stream() method. Then, we use the mapToInt() method to convert the stream of Integer objects to an IntStream, which allows us to perform numeric operations. Finally, we call the sum() method on the IntStream to calculate the sum of the numbers in the stream and then print it.
Java Streams provide several features that make it easy to process data collections concisely and efficiently. Here are some of the main features that streams provide:
Parallelism: Streams can be easily parallelized. This means that they can be split into multiple parts. Then, they are processed in parallel across multiple threads or processors. This can enhance performance for large datasets to a great extent.
Lazy Evaluation: As already mentioned, streams use lazy evaluation. This means intermediate operations are not executed until a terminal operation is called on the stream. This allows for more efficient use of resources and can improve performance for complex stream pipelines.
Method Chaining: Streams support method chaining. This allows multiple operations to be chained together into a single stream pipeline. This makes writing concise and readable codes that perform complex data transformations easy.
Non-mutating Operations: Streams provide a set of non-mutating operations that do not modify the original collection. However, these operations return a new stream with the desired changes instead. This can make it easier to reason about the code. It may also avoid unexpected side effects.
Functional Programming: Streams use functional programming concepts, such as higher-order functions and lambda expressions. It makes it easy to write expressive and reusable code.
Support for Different Data Sources: Streams can be created from various data sources, such as collections, arrays, or files. They can be easily converted into other data structures or formats.
Also Read: A Complete Guide to Java Keywords
The Java Stream interface provides several methods that allow you to perform various operations on a stream. Here are some of the Java stream interface methods:
Must Read: How to Use the Final Keyword in Java for Variables, Methods, and Classes
Now, let us look at an example of filtering a collection in Java using the Stream API:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
// Create a list of strings
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
names.add("David");
names.add("Eve");
// Filter the list to get names starting with "A"
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
// Print the filtered list
for (String name : filteredNames) {
System.out.println(name);
}
}
}
Here is an example of iterating over a Stream in Java:
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Create a Stream of integers from 1 to 5
Stream<Integer> stream = Stream.iterate(1, n -> n + 1)
.limit(5);
// Iterate over the Stream and print the elements
stream.forEach(System.out::println);
}
}
In this example, we create a Stream of integers using the Stream.iterate() method. The iterate() method takes an initial value (1 in this case) and a lambda expression that defines the function to generate the next value based on the previous value (n -> n + 1 in this case). We limit the stream to contain only 5 elements using the limit() method.
Here is an example of using the reduce() method with Stream in Java on a collection:
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
// Create a list of integers
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// Use reduce() to calculate the sum of the numbers
int sum = numbers.stream()
.reduce(0, Integer::sum);
System.out.println("Sum: " + sum);
}
}
Now, here is an example of using the Collectors method with Stream in Java for also calculating the sum of 1, 2, 3, 4, and 5:
Here's an example of using Stream in Java to find the maximum and minimum product prices from a collection:
Here is an example of using the count() method with Stream in Java to count the number of elements in a collection:
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
// Create a list of strings
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
// Use count() to get the number of elements
long count = names.stream().count();
System.out.println("Count: " + count);
}
}
Here is an example of using Stream in Java to convert a list into a set:
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
// Create a list of integers
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(3); // Duplicate element
// Convert the list to a set using Collectors.toSet()
Set<Integer> uniqueNumbers = numbers.stream()
.collect(Collectors.toSet());
// Print the unique numbers in the set
for (Integer number : uniqueNumbers) {
System.out.println(number);
}
}
}
Now, here is an example of using Stream in Java to convert a list into a map:
Streams in Java simplify the way developers handle data by enabling functional-style operations on collections. They provide efficient tools for filtering, mapping, reducing, and transforming data without modifying the original source. With features like lazy evaluation, method chaining, and parallel execution, Streams in Java make code more readable and performance-driven.
This tutorial explained their core concepts, operations, and examples to help you understand practical applications. Mastering the Stream API equips developers to build scalable, clean, and efficient Java programs, making it an essential concept for anyone learning or working with modern Java development.
Streams were introduced in Java 8 to simplify data processing by providing a functional programming approach. Before streams, developers relied heavily on loops and iterators, which made code verbose and harder to maintain. Streams allow cleaner pipelines for tasks like filtering, mapping, and reducing, while also supporting parallel execution. This shift improves performance, readability, and scalability in modern Java applications.
Collections store and manage data elements, while Streams in Java provide a functional way to process those elements. Collections are about data storage, whereas streams are about computation and transformation. Streams are also immutable, support lazy evaluation, and can be parallelized, unlike collections. This makes streams ideal for performing complex data operations without modifying the original source.
Intermediate operations in Java Streams return a new stream after applying transformations. Common examples include map(), filter(), and sorted(). These operations are lazy, meaning they don’t execute until a terminal operation is applied. This allows efficient handling of data pipelines by only processing elements when required, helping developers write optimized and concise data-processing code.
Terminal operations in Streams trigger the actual computation of data. They produce a result or a side effect rather than another stream. Examples include collect(), forEach(), reduce(), and count(). Once a terminal operation is performed, the stream is consumed and cannot be reused. This distinction is crucial for effectively handling stream pipelines in Java applications.
Yes, Streams in Java use lazy evaluation. Intermediate operations, such as map() or filter(), don’t execute immediately. They wait until a terminal operation like collect() or reduce() is called. This behavior improves efficiency, as only necessary elements are processed. Lazy evaluation also enables developers to build optimized pipelines for handling both small and large datasets effectively.
No, streams cannot be reused once a terminal operation is applied. After consumption, attempting to operate on the same stream will throw an IllegalStateException. If you need to process the same data again, you must create a new stream from the source. This ensures predictable and efficient behavior when handling data processing pipelines in Java.
The map() function transforms each element into another form, returning a stream of transformed values. In contrast, flatMap() flattens nested streams into a single stream. For example, map() may return multiple lists, whereas flatMap() combines those lists into one unified stream. This distinction is useful when handling nested collections like lists of lists in Java.
Parallel streams divide data into multiple chunks and process them across different threads concurrently. This is achieved by calling the parallelStream() method or converting a sequential stream using parallel(). Parallelism boosts performance for large datasets but should be used carefully, as thread management overhead may outweigh benefits for smaller collections or simple computations.
Streams in Java themselves are not thread-safe. If a stream is used concurrently across multiple threads without proper synchronization, it may cause unpredictable results. However, parallel streams internally manage threads safely for data processing. When working with shared mutable data sources, developers must ensure thread-safety by using synchronized collections or avoiding shared state.
Yes, Streams in Java can represent infinite data using methods like Stream.iterate() and Stream.generate(). These streams don’t store all elements in memory but produce values on demand using lazy evaluation. For example, Stream.iterate(1, n -> n + 1) creates an infinite stream of integers. Developers must limit infinite streams using methods like limit() to avoid unbounded execution.
The filter() method processes a stream and returns a new stream containing only elements that satisfy a given condition, defined as a Predicate. For example, filtering numbers greater than 10 or names starting with “A.” This operation enables developers to selectively process elements, making stream pipelines highly efficient and readable for complex filtering tasks in Java.
The reduce() method combines elements of a stream into a single result using a BinaryOperator. It is useful for aggregation tasks such as summing numbers, concatenating strings, or finding minimum and maximum values. Developers can also provide an identity value for initialization. Reduce exemplifies functional programming in Java, allowing concise representation of common mathematical and aggregation operations.
The collect() method is a terminal operation that gathers elements of a stream into collections like List, Set, or Map. It uses the Collectors utility class, which provides methods like toList(), toSet(), and toMap(). Collectors can also be customized for grouping or partitioning data, making them powerful for building structured results from complex stream pipelines.
Streams in Java are commonly used for filtering, mapping, reducing, sorting, and aggregating data from collections or arrays. They simplify tasks like processing employee records, transforming strings, finding maximum or minimum values, and computing sums or averages. Their functional style and method chaining make them ideal for building clean, concise, and efficient data-processing pipelines in real-world applications.
No, Streams in Java do not modify the original collection or data source. They work on copies of the data, producing new streams or results after applying transformations. This immutability ensures safer and more predictable behavior, avoiding accidental side effects. If modification is needed, the original collection must be updated explicitly outside the stream pipeline.
Short-circuiting refers to operations that can terminate a stream pipeline early without processing all elements. Examples include findFirst(), findAny(), limit(), and anyMatch(). For instance, findFirst() stops processing as soon as the first match is found. This feature enhances performance by avoiding unnecessary computations and makes Streams more efficient for certain queries or conditions.
Streams in Java can be created from various sources, including collections, arrays, files, or even infinite sequences. Common ways include collection.stream(), Arrays.stream(array), or Stream.of(elements). Developers can also use Stream.iterate() and Stream.generate() for custom streams. This flexibility ensures that streams can be integrated into almost any data-processing scenario in modern Java applications.
Sequential streams process elements one after another in a single thread, while parallel streams split tasks across multiple threads for concurrent execution. Parallel streams can improve performance for large datasets, but overhead from thread management may reduce benefits for smaller tasks. Developers must assess workload size and complexity before choosing between sequential or parallel processing in Streams.
Debugging Streams in Java can be challenging due to their functional style and method chaining. To simplify debugging, developers can use peek() as an intermediate operation to inspect elements at different stages of the pipeline. Alternatively, converting streams to collections temporarily may help in analyzing results. Proper logging and breakpoints also assist in understanding stream behavior.
Streams in Java encourage functional programming and simplify handling of large datasets. They reduce boilerplate code, improve readability, and allow developers to write clean, efficient, and parallelizable pipelines. Their immutability and lazy evaluation enhance performance while reducing side effects. As modern applications demand scalable and maintainable solutions, mastering Streams is essential for building robust Java software.
Take the Free Quiz on Java
Answer quick questions and assess your Java knowledge
FREE COURSES
Start Learning For Free
Author|900 articles published
Recommended Programs