Definition
- No boxing – primitive streams operate on raw
int,long,doublevalues without creating wrapper objects (Integer, Long, Double). - Numeric operations –
sum(),average(),min(),max(),summaryStatistics()are built-in terminal operations. - Range factories –
IntStream.range(0, 10)(exclusive) andrangeClosed(1, 10)(inclusive) generate sequential values. - Conversion –
mapToIntconverts Streamto IntStream; boxed()converts back;mapToObjconverts to Stream. - Performance – for 1M elements, IntStream allocates 0 objects vs ~16 MB of Integer objects for Stream
.
Stream
Understanding the Concepts
What are IntStream, LongStream, DoubleStream?
Why does boxing matter?
// Stream<Integer>: BOXING - each int becomes an Integer object
int sum1 = java.util.stream.Stream.of(1, 2, 3, 4, 5)
.reduce(0, Integer::sum); // unboxing on each add
// IntStream: NO BOXING - pure primitives
int sum2 = java.util.stream.IntStream.of(1, 2, 3, 4, 5).sum();
// Zero Integer objects created
What numeric operations are available?
import java.util.stream.IntStream;
IntStream.of(10, 20, 30, 40, 50).sum(); // 150
IntStream.of(10, 20, 30, 40, 50).average(); // OptionalDouble(30.0)
IntStream.of(10, 20, 30, 40, 50).min(); // OptionalInt(10)
IntStream.of(10, 20, 30, 40, 50).max(); // OptionalInt(50)
IntStream.of(10, 20, 30, 40, 50).summaryStatistics();
// IntSummaryStatistics{count=5, sum=150, min=10, average=30.0, max=50}
How do range and rangeClosed work?
IntStream.range(0, 5).toArray(); // [0, 1, 2, 3, 4] exclusive end
IntStream.rangeClosed(1, 5).toArray(); // [1, 2, 3, 4, 5] inclusive end
// Index-based iteration
IntStream.range(0, accounts.size()).forEach(i ->
System.out.println(i + ": " + accounts.get(i).id()));
How do you convert between object and primitive streams?
import java.util.stream.*;
// Stream<Trade> -> IntStream
IntStream quantities = trades.stream().mapToInt(Trade::getQuantity);
// IntStream -> Stream<Integer>
Stream<Integer> boxed = IntStream.rangeClosed(1, 5).boxed();
// IntStream -> Stream<String>
Stream<String> labels = IntStream.rangeClosed(1, 5)
.mapToObj(i -> "TRD-" + String.format("%03d", i));
// IntStream -> LongStream (widening)
LongStream widened = IntStream.of(1, 2, 3).asLongStream();
What about summaryStatistics?
summaryStatistics() computes count, sum, min, max, and average in a single pass.
package com.bank.service;
import java.util.IntSummaryStatistics;
import java.util.stream.IntStream;
public class StatsDemo {
public static void main(String[] args) {
int[] dailyTransactions = {150, 200, 175, 190, 210, 185, 195};
IntSummaryStatistics stats = IntStream.of(dailyTransactions)
.summaryStatistics();
System.out.println("Count: " + stats.getCount()); // 7
System.out.println("Sum: " + stats.getSum()); // 1305
System.out.println("Min: " + stats.getMin()); // 150
System.out.println("Max: " + stats.getMax()); // 210
System.out.println("Avg: " + stats.getAverage()); // 186.43
}
}
Why not always use IntStream?
You need Stream
// IntStream has no collect(Collectors.toList())
// IntStream.of(1, 2, 3).collect(Collectors.toList()); // COMPILE ERROR
// CORRECT: box first, then collect
List<Integer> list = IntStream.of(1, 2, 3).boxed().collect(Collectors.toList());
// Or use toList() on boxed stream
List<Integer> list = IntStream.of(1, 2, 3).boxed().toList();
What about money calculations?
For monetary calculations, use BigDecimal with Stream
// WRONG: DoubleStream for money
double total = accounts.stream().mapToDouble(a -> a.getBalance()).sum();
// Floating-point imprecision!
// CORRECT: BigDecimal with reduce
BigDecimal total = accounts.stream()
.map(Account::balance)
.reduce(BigDecimal.ZERO, BigDecimal::add);
What should a senior engineer know?
- summaryStatistics() computes count, sum, min, max, and average in a single pass.
- For monetary calculations, use BigDecimal with Stream
and reduce, not DoubleStream. - IntStream.range is useful for index-based iteration:
IntStream.range(0, list.size()).forEach(i -> ...). - Does DoubleStream have range? No. Use IntStream.range and mapToDouble for sequential doubles.
- IntStream.average() returns OptionalDouble, not double, because the stream might be empty.
Visual Overview
Conversion Bridge:
Stream<Trade> ──mapToInt──▶ IntStream
│
┌──────────────┼──────────────┐
▼ ▼ ▼
boxed() mapToObj() asLongStream()
│ │ │
▼ ▼ ▼
Stream<Integer> Stream<String> LongStream
Key Takeaway
IntStream, LongStream, and DoubleStream are primitive-specialized streams that avoid autoboxing and provide built-in numeric operations. Stream
The conversion methods form a complete bridge: mapToInt/Long/Double converts Stream
Remember one sentence: primitive streams avoid boxing overhead and provide built-in sum, average, range, and summaryStatistics that Stream
---