Java > Java Collections Framework > Iterators and Streams > Filtering and Mapping Data with Streams
Filtering and Mapping a List of Integers
This code snippet demonstrates how to use Java Streams to filter a list of integers and then map the filtered elements to their squares. Streams provide a concise and efficient way to process collections of data.
Code Example
The code initializes a list of integers. It then uses a stream to perform two operations: filtering and mapping. The filter
operation selects only the even numbers (n % 2 == 0
). The map
operation then transforms each selected number to its square (n * n
). Finally, collect(Collectors.toList())
gathers the transformed elements into a new list named evenSquares
. The original and processed lists are printed to the console.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamFilterMap {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Filter even numbers and then map them to their squares
List<Integer> evenSquares = numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println("Original numbers: " + numbers);
System.out.println("Even squares: " + evenSquares);
}
}
Concepts Behind the Snippet
This snippet utilizes two core concepts of Java Streams:
* Filtering: Selecting elements from a stream that match a specific condition. This is achieved using the filter()
method, which takes a predicate (a boolean-valued function) as input.
* Mapping: Transforming each element of a stream to another element. This is done using the map()
method, which applies a function to each element.
Streams provide a functional approach to data processing, allowing for concise and readable code.
Real-Life Use Case
Imagine you have a database of customer information, and you want to find all customers who have made purchases exceeding a certain amount and then create a list of their email addresses. You could achieve this easily using streams: filter customers by purchase amount, then map the filtered customers to their email addresses.
Best Practices
When using streams, consider the following:
* Keep operations short and focused: Each filter
and map
operation should ideally perform a single, well-defined task.
* Avoid side effects: Stream operations should not modify external state. They should be pure functions.
* Use parallel streams with caution: While parallel streams can improve performance, they introduce complexity and potential for race conditions. Consider them only when processing large datasets and after careful performance analysis.
Interview Tip
Be prepared to explain the difference between intermediate and terminal stream operations. filter
and map
are intermediate operations, meaning they return a new stream. collect
is a terminal operation, meaning it produces a result and ends the stream pipeline.
When to Use Them
Use streams when you need to perform complex data transformations on collections of data in a declarative and concise manner. They are particularly useful for filtering, mapping, sorting, and reducing data.
Memory Footprint
Streams are designed to be lazy, meaning they only process data when needed. This can lead to improved memory efficiency compared to traditional loop-based approaches, especially when dealing with large datasets. However, intermediate operations create temporary streams, so excessive use of intermediate operations can increase memory consumption.
Alternatives
Alternatives to streams include: * Traditional for loops: For loops provide more control but can be more verbose. * Enhanced for loops (for-each loops): Shorter than traditional for loops, but still less concise than streams. * External libraries (e.g., Apache Commons Collections): Offer specialized data structures and algorithms, but add dependencies to your project.
Pros
* Conciseness: Streams allow you to express complex data transformations in a compact and readable way. * Readability: The declarative style of streams makes code easier to understand. * Parallelism: Streams can be easily parallelized to improve performance. * Lazy evaluation: Streams only process data when needed, which can improve memory efficiency.
Cons
* Learning curve: Streams can be initially challenging to understand, especially for developers accustomed to imperative programming. * Debugging: Debugging streams can be more difficult than debugging traditional loops. * Overhead: Streams can introduce a small performance overhead compared to simple loops, especially for small datasets.
FAQ
-
What is a stream in Java?
A stream is a sequence of elements supporting sequential and parallel aggregate operations. Streams are not data structures; they are a way to process data from a source (such as a collection, array, or I/O channel). -
What is the difference between
filter
andmap
?
filter
selects elements based on a condition, whilemap
transforms elements into a new form.filter
reduces the number of elements, whilemap
changes the type or value of the elements. -
How do I convert a stream back to a list?
Use thecollect(Collectors.toList())
method to collect the elements of the stream into a new list.