Java 8
Stream API
Arrays
Functional Programming
Java Programming

Java 8 Stream and operation on arrays

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Java 8 brought significant enhancements to the Java programming language, one of the most important being the introduction of the Stream API. This API provides a powerful mechanism for processing sequences of elements and offers an abstraction level to enable functional-style operations on arrays and collections. The adoption of Streams has resulted in cleaner, more readable, and more concise code.

Introduction to Java 8 Streams

Streams are not a data structure but a sequence of data elements supporting sequential and parallel operations. These operations enable the processing of data declaratively and can effortlessly handle complex data transformations.

Key Characteristics of Streams

  1. No Storage: Streams hold no data; they are a view or pipeline over the data.
  2. Functional in Nature: Operations on streams produce results without modifying the underlying data source.
  3. Lazy Execution: Intermediate operations are lazy and only executed when a terminal operation is invoked.
  4. Possibility of Parallelism: Streams can be easily parallelized by calling the .parallel() method.

Stream Operations

Streams support two types of operations:

  • Intermediate Operations: These return a stream and support the creation of a pipeline. They're lazy and only executed when a terminal operation exists. Examples include map(), filter(), and distinct().
  • Terminal Operations: These produce a result or a side-effect, such as collecting the elements to a list or finding an average. Examples include collect(), forEach(), and reduce().

Streams and Arrays

While an array is not a Collection, you can construct a Stream from an array using Arrays.stream() or Stream.of().

Example: Working with Arrays and Streams

Consider the following examples that demonstrate how to transform, filter, and collect data:

java
1import java.util.Arrays;
2import java.util.List;
3import java.util.stream.Collectors;
4
5public class StreamExamples {
6
7    public static void main(String[] args) {
8        // Array of strings
9        String[] names = {"Alice", "Bob", "Charlie", "David"};
10
11        // Convert the array to a list, filter by length, sort, and collect
12        List<String> resultList = Arrays.stream(names)
13            .filter(name -> name.length() > 3)
14            .sorted()
15            .collect(Collectors.toList());
16
17        System.out.println(resultList);
18    }
19}

This example demonstrates the following operations on an array:

  • Filter: Excludes names with 3 or fewer characters.
  • Sort: Arranges the remaining names in ascending order.
  • Collect: Gathers the elements into a List.

Stream Pipeline

A stream pipeline consists of:

  1. Source: An array, collection, or I/O channel.
  2. Zero or more Intermediate Operations: Processes the elements into a new stream.
  3. Terminal Operation: Executes the pipeline and produces a result.

Advanced Examples and Use Cases

Summing Elements of an Integer Array

Using reduce(), you can sum the elements in a stream:

java
1int[] numbers = {1, 2, 3, 4, 5};
2int sum = Arrays.stream(numbers)
3               .reduce(0, Integer::sum);
4System.out.println("Sum: " + sum);

Finding Maximum Value

To find a maximum value in an array using streams:

java
1int max = Arrays.stream(numbers)
2              .max()
3              .orElseThrow(NoSuchElementException::new);
4System.out.println("Max: " + max);

Parallel Stream Example

Parallel streams can improve performance by dividing tasks into subtasks across multiple threads:

java
1int[] largeArray = new int[1000000];
2// Initialize the array
3// ...
4
5long startTime = System.nanoTime();
6
7int sumParallel = Arrays.stream(largeArray)
8    .parallel()
9    .sum();
10
11long duration = System.nanoTime() - startTime;
12System.out.println("Parallel Sum: " + sumParallel + " in " + duration + " ns");

Summary Table

FeatureDescription
SourceConstructed from arrays, collections, or I/O channels.
Intermediate OpsIncludes operations like map, filter, and sorted.
Terminal OpsIncludes operations like collect, reduce, and forEach.
Lazy ExecutionIntermediate operations are not executed until a terminal operation.
Stateless/StatefulIntermediate operations may be stateless (e.g., map) or stateful.
Sequential/ParallelStreams can be processed in parallel, improving performance.

Conclusion

Java 8's Stream API is a powerful tool for processing sequences of data in a functional style. It inherently supports both sequential and parallel processing, making it an ideal choice for many applications. Its ease of use, coupled with enhanced performance when leveraged correctly, makes it an integral part of modern Java programming. As developers, understanding and employing streams effectively can lead to more efficient and expressive code.


Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.