IntStream, LongStream, DoubleStream in Java

Introduction

Java's primitive specialized streams - IntStream, LongStream, and DoubleStream - provide efficient alternatives to generic Stream<T> for working with primitive data types. These streams eliminate boxing overhead and offer specialized operations for numerical computations, making them essential for high-performance applications.

IntStream

Creation Methods

public class IntStreamExamples {
public void demonstrateCreation() {
// Range operations
IntStream range1 = IntStream.range(1, 10);        // 1 to 9 (exclusive)
IntStream range2 = IntStream.rangeClosed(1, 10);  // 1 to 10 (inclusive)
// From arrays
int[] numbers = {1, 2, 3, 4, 5};
IntStream fromArray = IntStream.of(numbers);
IntStream fromValues = IntStream.of(1, 2, 3, 4, 5);
// From other sources
IntStream generated = IntStream.generate(() -> (int) (Math.random() * 100))
.limit(10);
IntStream iterated = IntStream.iterate(0, n -> n + 2).limit(5);
// Empty stream
IntStream empty = IntStream.empty();
}
}

Common Operations

public class IntStreamOperations {
public void demonstrateOperations() {
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Statistical operations
IntSummaryStatistics stats = IntStream.of(numbers)
.summaryStatistics();
System.out.println("Count: " + stats.getCount());
System.out.println("Sum: " + stats.getSum());
System.out.println("Min: " + stats.getMin());
System.out.println("Max: " + stats.getMax());
System.out.println("Average: " + stats.getAverage());
// Aggregation operations
int sum = IntStream.of(numbers).sum();
OptionalInt max = IntStream.of(numbers).max();
OptionalInt min = IntStream.of(numbers).min();
OptionalDouble average = IntStream.of(numbers).average();
// Searching operations
OptionalInt firstEven = IntStream.of(numbers)
.filter(n -> n % 2 == 0)
.findFirst();
boolean anyMatch = IntStream.of(numbers)
.anyMatch(n -> n > 5);
boolean allMatch = IntStream.of(numbers)
.allMatch(n -> n > 0);
}
}

Advanced IntStream Usage

public class AdvancedIntStream {
public void demonstrateAdvancedUsage() {
// Generate prime numbers
IntStream primes = IntStream.rangeClosed(2, 100)
.filter(this::isPrime);
// Pythagorean triples
IntStream.rangeClosed(1, 50)
.boxed()
.flatMap(a -> 
IntStream.rangeClosed(a, 50)
.filter(b -> Math.sqrt(a * a + b * b) % 1 == 0)
.mapToObj(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)})
)
.limit(10)
.forEach(triple -> System.out.println(
Arrays.toString(triple)));
// Factorial calculation
int factorial = IntStream.rangeClosed(1, 5)
.reduce(1, (a, b) -> a * b);
}
private boolean isPrime(int number) {
return IntStream.rangeClosed(2, (int) Math.sqrt(number))
.allMatch(n -> number % n != 0);
}
// Matrix operations with IntStream
public void matrixOperations() {
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Sum of all elements
int totalSum = Arrays.stream(matrix)
.flatMapToInt(IntStream::of)
.sum();
// Row sums
int[] rowSums = Arrays.stream(matrix)
.mapToInt(row -> IntStream.of(row).sum())
.toArray();
// Column sums
int[] colSums = IntStream.range(0, matrix[0].length)
.map(col -> Arrays.stream(matrix)
.mapToInt(row -> row[col])
.sum())
.toArray();
}
}

LongStream

Creation and Operations

public class LongStreamExamples {
public void demonstrateLongStream() {
// Creation methods
LongStream range = LongStream.range(1L, 1_000_000L);
LongStream generated = LongStream.generate(() -> 
ThreadLocalRandom.current().nextLong(1000L))
.limit(100);
// Working with large numbers
long largeSum = LongStream.rangeClosed(1L, 10_000_000L)
.parallel()  // Efficient for large ranges
.sum();
// Statistical operations with large datasets
LongSummaryStatistics stats = LongStream.range(0L, 1_000_000L)
.map(n -> n * n)  // Squares of numbers
.summaryStatistics();
System.out.println("Large number stats: " + stats);
// Time measurement example
long startTime = System.nanoTime();
long result = LongStream.range(1L, 100000L)
.filter(n -> n % 2 == 0)
.map(n -> n * 2)
.sum();
long duration = System.nanoTime() - startTime;
System.out.println("Computation took: " + duration + " ns");
}
// Fibonacci sequence with LongStream
public void fibonacciSequence() {
LongStream fibonacci = LongStream.iterate(
new long[]{0L, 1L},
pair -> new long[]{pair[1], pair[0] + pair[1]})
.mapToLong(pair -> pair[0])
.limit(20);
fibonacci.forEach(System.out::println);
}
// Prime number generation for large numbers
public void largePrimeNumbers() {
LongStream largePrimes = LongStream.rangeClosed(1_000_000L, 1_000_100L)
.filter(this::isPrime)
.parallel();
largePrimes.forEach(prime -> 
System.out.println("Large prime: " + prime));
}
private boolean isPrime(long number) {
if (number < 2) return false;
return LongStream.rangeClosed(2, (long) Math.sqrt(number))
.allMatch(n -> number % n != 0);
}
}

DoubleStream

Creation and Mathematical Operations

public class DoubleStreamExamples {
public void demonstrateDoubleStream() {
// Creation from various sources
DoubleStream fromValues = DoubleStream.of(1.5, 2.7, 3.9, 4.2);
DoubleStream generated = DoubleStream.generate(Math::random)
.limit(100);
DoubleStream iterated = DoubleStream.iterate(1.0, x -> x * 1.1)
.limit(10);
// Mathematical operations
double[] data = {1.2, 2.3, 3.4, 4.5, 5.6};
DoubleSummaryStatistics stats = DoubleStream.of(data)
.summaryStatistics();
System.out.println("Double Statistics: " + stats);
// Specialized mathematical operations
double sumOfSquares = DoubleStream.of(data)
.map(x -> x * x)
.sum();
double standardDeviation = Math.sqrt(
DoubleStream.of(data)
.map(x -> x - stats.getAverage())
.map(x -> x * x)
.sum() / stats.getCount()
);
}
// Scientific computations
public void scientificComputations() {
// Numerical integration - calculating π
double pi = DoubleStream.generate(Math::random)
.limit(1_000_000)
.parallel()
.mapToObj(x -> {
double xVal = x;
double yVal = Math.random();
return Math.sqrt(xVal * xVal + yVal * yVal) <= 1.0 ? 1 : 0;
})
.mapToDouble(val -> (double) val)
.average()
.orElse(0.0) * 4.0;
System.out.println("Approximated π: " + pi);
// Exponential function series expansion
double x = 2.0;
double exponential = DoubleStream.iterate(0, n -> n + 1)
.limit(20)
.map(n -> Math.pow(x, n) / factorial(n))
.sum();
System.out.println("e^" + x + " ≈ " + exponential);
}
private double factorial(double n) {
return DoubleStream.iterate(1.0, i -> i + 1.0)
.limit((long) n)
.reduce(1.0, (a, b) -> a * b);
}
// Statistical analysis
public void statisticalAnalysis() {
double[] dataset = {23.5, 45.2, 12.8, 78.9, 34.1, 56.7, 89.3, 67.8};
double mean = DoubleStream.of(dataset).average().orElse(0.0);
double variance = DoubleStream.of(dataset)
.map(x -> Math.pow(x - mean, 2))
.average()
.orElse(0.0);
double stdDev = Math.sqrt(variance);
System.out.printf("Mean: %.2f, Variance: %.2f, Std Dev: %.2f%n", 
mean, variance, stdDev);
// Normalization
double[] normalized = DoubleStream.of(dataset)
.map(x -> (x - mean) / stdDev)
.toArray();
System.out.println("Normalized data: " + Arrays.toString(normalized));
}
}

Conversion Between Stream Types

public class StreamConversionExamples {
public void demonstrateConversions() {
// IntStream conversions
IntStream intStream = IntStream.range(1, 6);
// To boxed Stream
Stream<Integer> boxedStream = intStream.boxed();
// To other primitive streams
LongStream longStream = intStream.asLongStream();
DoubleStream doubleStream = intStream.asDoubleStream();
// From boxed stream to primitive stream
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
IntStream fromBoxed = integerStream.mapToInt(Integer::intValue);
// Array conversions
int[] intArray = IntStream.range(1, 6).toArray();
Integer[] integerArray = IntStream.range(1, 6)
.boxed()
.toArray(Integer[]::new);
}
// Mapping between stream types
public void streamMapping() {
// IntStream to DoubleStream with transformation
DoubleStream squares = IntStream.range(1, 10)
.mapToDouble(n -> Math.pow(n, 2));
// DoubleStream to IntStream with rounding
IntStream rounded = DoubleStream.of(1.2, 2.7, 3.5, 4.9)
.mapToInt(d -> (int) Math.round(d));
// Complex transformation chain
LongStream result = IntStream.range(1, 100)
.filter(n -> n % 2 == 0)
.mapToLong(n -> (long) n * n)  // Convert to long to avoid overflow
.filter(n -> n > 1000);
}
}

Parallel Processing with Primitive Streams

public class ParallelPrimitiveStreams {
public void demonstrateParallelProcessing() {
// Parallel IntStream - ideal for CPU-intensive operations
long parallelSum = IntStream.range(1, 1_000_000)
.parallel()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.sum();
System.out.println("Parallel sum: " + parallelSum);
// Performance comparison
int size = 10_000_000;
long sequentialTime = measureTime(() -> 
IntStream.range(0, size)
.map(n -> intensiveCalculation(n))
.sum()
);
long parallelTime = measureTime(() -> 
IntStream.range(0, size)
.parallel()
.map(n -> intensiveCalculation(n))
.sum()
);
System.out.printf("Sequential: %dms, Parallel: %dms%n", 
sequentialTime, parallelTime);
}
private int intensiveCalculation(int n) {
// Simulate CPU-intensive work
return IntStream.range(0, 1000)
.reduce(n, (a, b) -> a ^ b);
}
private long measureTime(Runnable operation) {
long start = System.currentTimeMillis();
operation.run();
return System.currentTimeMillis() - start;
}
// Thread-safe operations with parallel streams
public void threadSafeOperations() {
// Using concurrent collections for parallel stream results
List<Integer> threadSafeList = Collections.synchronizedList(new ArrayList<>());
IntStream.range(0, 1000)
.parallel()
.filter(n -> n % 3 == 0)
.forEach(threadSafeList::add);
// Reduction operations are thread-safe
int product = IntStream.range(1, 10)
.parallel()
.reduce(1, (a, b) -> a * b);
System.out.println("Parallel product: " + product);
}
}

Real-World Use Cases

1. Data Analysis

public class DataAnalysisWithPrimitiveStreams {
public void analyzeSalesData() {
double[] sales = {12500.50, 23400.75, 18900.25, 26700.80, 31200.40};
DoubleSummaryStatistics salesStats = DoubleStream.of(sales)
.summaryStatistics();
System.out.println("Sales Analysis:");
System.out.printf("Total: $%,.2f%n", salesStats.getSum());
System.out.printf("Average: $%,.2f%n", salesStats.getAverage());
System.out.printf("Best Month: $%,.2f%n", salesStats.getMax());
System.out.printf("Worst Month: $%,.2f%n", salesStats.getMin());
// Identify months above average
long aboveAverage = DoubleStream.of(sales)
.filter(amount -> amount > salesStats.getAverage())
.count();
System.out.println("Months above average: " + aboveAverage);
}
// Sensor data processing
public void processSensorData() {
int[] sensorReadings = {23, 25, 22, 24, 26, 25, 23, 27, 24, 22};
// Remove outliers and calculate average
double average = IntStream.of(sensorReadings)
.sorted()
.skip(2)  // Remove lowest 2
.limit(sensorReadings.length - 4)  // Remove highest 2
.average()
.orElse(0.0);
System.out.println("Filtered sensor average: " + average);
}
}

2. Game Development

public class GameDevelopmentStreams {
// Character attribute generation
public void generateCharacterStats() {
Random random = new Random();
// Generate 6 ability scores (4d6 drop lowest)
int[] abilityScores = IntStream.generate(() -> 
random.ints(4, 1, 7)  // 4 dice rolls
.sorted()
.skip(1)          // drop lowest
.sum())           // sum remaining 3
.limit(6)                 // 6 ability scores
.toArray();
System.out.println("Ability scores: " + Arrays.toString(abilityScores));
// Calculate modifiers
int[] modifiers = IntStream.of(abilityScores)
.map(score -> (score - 10) / 2)
.toArray();
System.out.println("Ability modifiers: " + Arrays.toString(modifiers));
}
// Experience point calculations
public void experienceCalculations() {
int[] monsterXP = {50, 100, 200, 450, 700, 1100, 1800, 2300};
// Total XP for encounter
int totalXP = IntStream.of(monsterXP).sum();
// Adjusted XP for multiple monsters
double adjustedXP = totalXP * getMultiplier(monsterXP.length);
System.out.printf("Total XP: %d, Adjusted XP: %.1f%n", 
totalXP, adjustedXP);
}
private double getMultiplier(int monsterCount) {
return switch (monsterCount) {
case 1 -> 1.0;
case 2 -> 1.5;
case 3, 4, 5, 6 -> 2.0;
case 7, 8, 9, 10 -> 2.5;
case 11, 12, 13, 14 -> 3.0;
default -> 4.0;
};
}
}

Performance Considerations and Best Practices

public class StreamPerformanceBestPractices {
public void performanceTips() {
// 1. Use primitive streams to avoid boxing overhead
long sum = IntStream.range(1, 1000000).sum();  // Good
// vs
long sumBoxed = Stream.iterate(1, n -> n + 1)
.limit(1000000)
.mapToInt(Integer::intValue)
.sum();  // Boxing overhead
// 2. Use range/rangeClosed for sequential integers
IntStream.range(0, 1000)  // Efficient
.forEach(i -> {});
// 3. Prefer method references
DoubleStream.of(1.0, 2.0, 3.0)
.map(Math::sqrt)  // Good - method reference
.toArray();
// 4. Use parallel streams for large, CPU-intensive operations
long largeSum = LongStream.range(1, 10000000)
.parallel()
.filter(n -> n % 2 == 0)
.sum();
// 5. Avoid stateful operations in parallel streams
int[] badParallel = IntStream.range(1, 1000)
.parallel()
.sorted()  // Stateful - can hurt performance
.toArray();
}
// Memory efficiency with large datasets
public void memoryEfficientProcessing() {
// Process large datasets in chunks
int chunkSize = 10000;
long total = 0;
for (int i = 0; i < 1_000_000; i += chunkSize) {
int chunkSum = IntStream.range(i, Math.min(i + chunkSize, 1_000_000))
.sum();
total += chunkSum;
}
System.out.println("Total with chunking: " + total);
}
}

Conclusion

Primitive specialized streams (IntStream, LongStream, DoubleStream) offer significant performance benefits over their boxed counterparts by eliminating autoboxing overhead and providing specialized operations for numerical computations. They are particularly valuable for:

  • Mathematical computations and statistical analysis
  • Large dataset processing with parallel execution
  • Game development and simulation calculations
  • Scientific computing and data analysis
  • Performance-critical applications where every CPU cycle counts

By understanding the strengths and appropriate use cases for each primitive stream type, developers can write more efficient and expressive code for numerical processing in Java.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper