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 and map?

    filter selects elements based on a condition, while map transforms elements into a new form. filter reduces the number of elements, while map changes the type or value of the elements.
  • How do I convert a stream back to a list?

    Use the collect(Collectors.toList()) method to collect the elements of the stream into a new list.