Java 8
Streams API
collect method
reduce function
functional programming

Java 8 Streams - collect vs reduce

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Java 8 introduced the Stream API, a major enhancement to the Java collection framework, which facilitates functional-style operations on streams of elements. The Stream API provides several operations to perform tasks such as filtering, mapping, and reducing over elements. Among the various terminal operations, collect and reduce stand out for their ability to transform and accumulate data. This article delves into the differences and use cases of collect vs reduce.

Understanding Streams

Streams in Java 8 are not data structures but a sequence of elements provided by a source, enabling parallel execution and aggregation operations. They allow operations such as filtering, mapping, and reduction to be performed in a declarative manner. Unlike collections, streams do not store elements; instead, they carry elements from a source (e.g., a collection) through a pipeline of intermediate and terminal operations.

Terminal Operations: Collect vs Reduce

Collect

The collect method is a terminal operation that transforms the elements of a stream into a different form, most commonly a List, Set, or Map. The collect operation requires a Collector, which defines how the transformation or accumulation should happen. The Java standard library provides several collectors through the Collectors utility class.

java
1List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
2
3// Use collect to gather names into a List
4List<String> upperCaseNames = names.stream()
5    .map(String::toUpperCase)
6    .collect(Collectors.toList());
7
8System.out.println(upperCaseNames); // Output: [ALICE, BOB, CHARLIE]

Collectors Utility Methods

  • toList(): Collects elements into a List.
  • toSet(): Collects elements into a Set.
  • toMap(): Collects elements into a Map.
  • joining(): Concatenates elements into a String.
  • groupingBy(): Groups elements by a classifier function.
  • partitioningBy(): Partitions elements into two groups based on a predicate.

Reduce

The reduce method performs a reduction on the elements of a stream using an associative accumulation function and returns an Optional describing the reduced value. It's a more general-purpose method than collect and is typically used for arithmetic operations or when the result is a single value.

java
1List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
2
3// Use reduce to compute the sum of numbers
4int sum = numbers.stream()
5    .reduce(0, Integer::sum);
6
7System.out.println(sum); // Output: 15

Reduction Variants

  1. Binary Operator: A version of reduce which takes a binary operator with no identity value, returning an Optional.
java
   Optional<Integer> product = numbers.stream()
       .reduce((a, b) -> a * b);
   System.out.println(product); // Output: Optional[120]
  1. Identity + Accumulator: Takes an identity value and a binary accumulator.
java
   int product = numbers.stream()
       .reduce(1, (a, b) -> a * b);
   System.out.println(product); // Output: 120

Key Differences and Use Cases

FeatureCollectReduce
PurposeTo transform elements into a different form (e.g., collection)To aggregate elements to a single value
Output TypeAny object determined by the CollectorSingle value, encapsulated in Optional
Use of CollectorYes (from Collectors utility methods)No
Common Use CasesCreating collections, joining strings, grouping dataSummation, product, maximum, minimum
FlexibilityFlexible due to customizable collectorsSimpler but not suitable for all cases

Conclusion

Understanding when to use collect vs reduce is vital for Java developers utilizing streams. Use collect when you need to transform elements into a new form, such as creating a collection or a complex aggregation of data. Opt for reduce when you need to compute a single aggregated result, such as a sum or product.

While both serve to aggregate data in some capacity, they excel in different scenarios. Choosing the right method will result in cleaner and more efficient code, taking full advantage of the Stream API’s power and expressiveness. As you design your stream pipelines, consider the final output and opt for the terminal operation that aligns best with your needs.


Course illustration
Course illustration

All Rights Reserved.