How Does Stream Differ from Collection in Java?

How Does Stream Differ from Collection in Java?

Introduction to Java Collections

The Collection framework in Java is a fundamental part of the language. It provides a set of interfaces, classes, and methods that help developers manage groups of objects. The primary interfaces in the Collection framework include List, Set, and Queue, with their respective concrete implementations such as ArrayList, HashSet, and LinkedList.

A Collection is a data structure that stores elements in a specific way, offering operations like insertion, deletion, and lookup. Collections in Java are mutable, meaning their contents can be changed.

// Example of a Collection in Java
import java.util.ArrayList;
import java.util.Collection;

public class CollectionExample {
    public static void main(String[] args) {
        Collection collection = new ArrayList<>();
        collection.add("Apple");
        collection.add("Banana");
        collection.add("Orange");

        System.out.println(collection); // Output: [Apple, Banana, Orange]
    }
}
            

Understanding Java Streams

Introduced in Java 8, Stream is part of the java.util.stream package. A Stream represents a sequence of elements that can be processed in parallel or sequentially. It is designed to perform aggregate operations (such as filtering, mapping, or reducing) on data in a declarative manner, leveraging the power of lambda expressions and functional-style programming.

Stream is not a data structure; it doesn’t store data. Instead, it provides a pipeline for transforming data from a source, such as a Collection or an array, into another form, potentially with side-effects (e.g., printing values or modifying external state). Streams support operations like filtering, mapping, and reducing data in a concise, readable way.

// Example of using Stream in Java
import java.util.List;
import java.util.stream.Collectors;

public class StreamExample {
    public static void main(String[] args) {
        List fruits = List.of("Apple", "Banana", "Orange", "Grape", "Peach");

        // Using stream to filter and collect items
        List longFruits = fruits.stream()
                                       .filter(fruit -> fruit.length() > 5)
                                       .collect(Collectors.toList());

        System.out.println(longFruits); // Output: [Banana, Orange]
    }
}
            

Key Differences Between Stream and Collection

While both Stream and Collection deal with groups of objects, they differ in several significant ways:

1. Mutability

Collection is mutable. You can add, remove, or modify elements in a collection, whereas a Stream is immutable. Once a stream is created, it cannot be modified. Streams are meant for performing operations on a sequence of elements, rather than modifying the sequence itself.

2. Lazy Evaluation

Streams are lazily evaluated. This means that the operations on streams (like filtering or mapping) are not executed until the terminal operation is invoked, such as forEach(), collect(), or reduce(). This allows for optimization, like short-circuiting the stream processing when possible.

// Lazy evaluation example with Stream
import java.util.List;

public class LazyEvaluationExample {
    public static void main(String[] args) {
        List numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9);

        // Using stream to filter and find the first even number
        int result = numbers.stream()
                            .filter(n -> n % 2 == 0)
                            .findFirst() // Terminal operation that triggers stream evaluation
                            .orElse(-1);
        
        System.out.println(result); // Output: 2
    }
}
            

3. Side Effects

Collections allow direct modification of the elements within the collection. You can perform side-effect operations such as modifying elements or removing them. On the other hand, streams are intended to avoid side effects. They focus on declarative operations like mapping and filtering, which do not change the source data.

4. Parallel Processing

Streams allow you to process data in parallel. By calling the parallelStream() method, you can easily perform operations in parallel, making better use of multicore processors. Collections, however, do not support parallel operations directly. The stream API simplifies the implementation of parallel processing.

// Parallel Stream Example
import java.util.List;

public class ParallelStreamExample {
    public static void main(String[] args) {
        List numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9);

        // Using parallel stream to sum elements in parallel
        int sum = numbers.parallelStream()
                         .mapToInt(Integer::intValue)
                         .sum();
        
        System.out.println(sum); // Output: 45
    }
}
            

5. Termination vs Intermediate Operations

Collection allows various direct operations on the data like adding, removing, or iterating over the elements. In contrast, Stream operations are divided into intermediate and terminal operations. Intermediate operations (such as filter(), map(), and distinct()) return a new stream and are lazily evaluated. Terminal operations (like collect(), reduce(), or forEach()) trigger the execution of the stream pipeline.

6. Syntax and Usage

Working with a Collection typically involves imperative programming style, where you write explicit loops and checks. On the other hand, Stream embraces functional programming concepts, making the code more concise and expressive. For example, you can perform filtering, mapping, and aggregation operations in a single, fluent expression using streams.

7. Collection Size

Since a stream is designed to work with any data source, including large datasets, it does not necessarily store its elements. A stream can represent infinite data sources like a generator or an endless sequence. A Collection, on the other hand, is bounded by memory, as it physically stores its elements.

When to Use Stream and Collection?

Choosing between Stream and Collection depends on the problem you’re trying to solve:

  • Use a Collection: When you need to store and manipulate a group of objects directly, and the collection’s size is fixed or small enough to fit in memory.
  • Use a Stream: When you need to process elements in a pipeline, perform transformations, and aggregate results in a declarative manner. Streams are also ideal for working with large or infinite data sources, especially when you want to exploit parallel processing.

© 2025 Tech Interview Guide. All Rights Reserved.

Please follow and like us:

Leave a Comment