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.