Back to: Java Tutorials
In this tutorial, learn about the powerful Java Stream API and how it simplifies complex data manipulation tasks. Explore examples and use cases.
Introduction
Java Stream API is a powerful tool for working with collections in Java. It was introduced in Java 8 and has quickly become one of the most popular features of the language. In this article, we will explore the Java Stream API and how it can be used to manipulate and process data in a more concise and efficient way.
What is Java Stream API?
Java Stream API is a high-level API for processing collections in Java. It provides a set of operations that can be applied to a collection of objects, such as filtering, mapping, and reducing. Streams allow developers to perform complex data manipulations in a concise and readable way.
Streams are not collections themselves, but rather a way to operate on collections. They are designed to be used once and then discarded, which means they do not modify the underlying data source. Instead, they produce a new stream or a result.
Streams are also lazy, meaning that they do not start processing the data until an operation that requires the result is called. This can lead to significant performance improvements when working with large collections of data.
Creating a Stream
Streams can be created from any collection in Java, such as List, Set, or Map. To create a stream, simply call the stream() method on the collection:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
Stream<String> stream = names.stream();
This code creates a stream of strings from the List “names”. Once we have a stream, we can perform operations on it to manipulate the data.
Operations on Streams
The Stream API provides two types of operations: intermediate and terminal.
Intermediate operations are operations that return a new stream. They are used to transform the data in the stream, such as filtering, mapping, or sorting. Intermediate operations are lazy, which means they do not start processing the data until a terminal operation is called.
Terminal operations are operations that produce a result, such as a single value, a collection, or an output to the console. Terminal operations are eager, which means they start processing the data immediately.
Filtering
One of the most common operations in the Stream API is filtering. This operation allows us to select elements from a stream based on a given condition. For example, we can filter a list of names to only include names that start with the letter “A”:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
Stream<String> stream = names.stream();
Stream<String> filteredStream = stream.filter(name -> name.startsWith("A"));
In this code, we first create a stream of strings from the List “names”. We then call the filter() method to create a new stream that only contains strings starting with the letter “A”.
Mapping
Mapping is another common operation in the Stream API. This operation allows us to transform the elements of a stream from one type to another. For example, we can map a list of strings to a list of their lengths:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
Stream<String> stream = names.stream();
Stream<Integer> lengthStream = stream.map(name -> name.length());
In this code, we first create a stream of strings from the List “names”. We then call the map() method to create a new stream that contains the length of each string.
Reducing
Reducing is an operation in the Stream API that allows us to combine all the elements of a stream into a single result. For example, we can reduce a list of numbers to their sum:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream();
int sum = stream.reduce(0, (a, b) -> a + b);
In this code, we first create a stream of integers from the List “numbers”. We then call the reduce() method to combine all the elements into a single result. The first argument to reduce() is the initial value of the result, which is 0 in this case. The second argument is a lambda expression that takes two integers and returns their sum.
Other Operations
In addition to filtering, mapping, and reducing, the Stream API provides many other operations that can be used to manipulate and process data. Some of these operations include:
- sorted(): sorts the elements of a stream in natural order or using a comparator.
- distinct(): removes duplicate elements from a stream.
- limit(): limits the size of a stream to a specified number of elements.
- skip(): skips a specified number of elements in a stream.
- forEach(): performs an action for each element in a stream.
Date and Time API
Java 8 also introduced a new Date and Time API that can be used with the Stream API. The new API is more comprehensive than the previous Date and Calendar APIs and provides better support for time zones, daylight saving time, and leap years.
To create a date or time object using the new API, we can use the following code:
LocalDate date = LocalDate.of(2023, 4, 7);
LocalTime time = LocalTime.of(11, 30);
LocalDateTime dateTime = LocalDateTime.of(date, time);
We can also create a ZonedDateTime object that includes the time zone:
ZoneId zoneId = ZoneId.of("America/New_York");
ZonedDateTime zonedDateTime = ZonedDateTime.of(dateTime, zoneId);
Once we have a date or time object, we can use it with the Stream API to perform operations such as filtering, mapping, and reducing.
Java Stream API Examples
Here is a complete code example that demonstrates the uses of Java Stream API:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
// Create a list of integers
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Example 1: Filter and print even numbers
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println("Even numbers: " + evenNumbers);
// Example 2: Map and print squares of numbers
List<Integer> squares = numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println("Squares: " + squares);
// Example 3: Reduce and print sum of numbers
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
System.out.println("Sum: " + sum);
}
}
Output:
In Example 1, we use the filter()
method to filter out only even numbers from the list. The collect()
method is then used to collect the filtered elements into a new list. The output shows the even numbers [2, 4, 6, 8, 10]
.
In Example 2, we use the map()
method to calculate the squares of each number in the list. The collect()
method is then used to collect the mapped elements into a new list. The output shows the squares [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
.
In Example 3, we use the reduce()
method to sum up all the numbers in the list. The reduce()
method takes two arguments: an initial value of the sum (which is 0 in this case), and a lambda expression that adds two numbers together. The output shows the sum of all the numbers in the list, which is 55
.
Conclusion
Java Stream API is a powerful tool for manipulating and processing collections in Java. It provides a set of operations that can be used to filter, map, and reduce data in a more concise and efficient way. The API is lazy and allows for significant performance improvements when working with large collections of data. Java 8 also introduced a new Date and Time API that can be used with the Stream API to provide better support for time zones, daylight saving time, and leap years. By mastering the Stream API, Java developers can write more concise, readable, and performant code.
Also, see the example code JavaExamples_NoteArena in our GitHub repository. See complete examples in our GitHub repositories.
Follow us on social media
Follow Author