# Numeric StreamsJ8 Home « Numeric Streams

In the Array Type Streams lesson we got a first look at using some of the overloaded `stream()` methods of the `Arrays` class. We also learnt that if your streaming arrays of objects then the `Stream.of` static method and the `Arrays.stream()` method both end up using `Arrays.stream()` under the bonnet. However we found that if you're streaming primitive type arrays then using the `Arrays.stream()` variants that were built for this purpose is best practice as they produce streams pertinent to the input:

1. `double[]` --> `DoubleStream`
2. `int[]` --> `IntStream`
3. `long[]` --> `LongStream`

In this lesson we look at these streams in greater detail along with some useful methods available in their interfaces.

### Using `IntStream` Top

We will be using methods from the `IntStream` interface for our examples, the variants of these methods are available in the `DoubleStream` and `LongStream` interfaces.

Following is a `TestIntStreamA` class to demonstrate usage of some of the methods of the `IntStream` interface.

``````
package info.java8;

import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Collectors;

/* Create streams from arrays */
public class TestIntStreamA {

public static void main(String[] args) {

// Create an array and stream it
int[] intArray = {16, 8, 3, 12, 16, 5, 1, 2, 12};
IntStream intStream = Arrays.stream(intArray);
intStream.forEach(System.out::print);

IntStream intStream2 = Arrays.stream(intArray);
long total = intStream2.distinct()
.sum();
System.out.println("\nThe distinct numbers in the array add up to: " + total);

// Get stream statistics
IntStream intStream3 = Arrays.stream(intArray);
IntSummaryStatistics stats = intStream3.collect(IntSummaryStatistics::new,
IntSummaryStatistics::accept,
IntSummaryStatistics::combine);
System.out.println("Statistic for this stream: " + stats);

// Box and collect to list
List<Integer> ints = IntStream.of(16, 8, 3, 12, 16)
.boxed()
.collect(Collectors.toList());
System.out.println("Integers in List collection: " + ints);

// Collect to array
int intArray2[] = IntStream.of(16, 8, 3, 12, 16)
.toArray();
for (int j : intArray2) {
System.out.println("int: " + j);
}
}
}

``````

Building and running the `TestIntStreamA` class produces the following output:

Lets go though the code and see what's new!

We use the `distinct()` method which returns a stream consisting of the distinct elements of this stream and the `sum()`method which returns the sum of elements in this stream, for the first time.

We create an `IntSummaryStatistics` object from an `IntStream` which collects statistics such as count, min, max, sum, and average and print off these statistics.

We can't store primitives in collections as they are generic so we use the handy `boxed()` method to wrap some ints and use the `collect` method along with `Collectors.toList()` to store the results in a `List<E>` which we print off. We look at collectors in more detail in the Stream Collectors lesson.

### Replacing Simple `for` Construct Top

There are lots of useful methods in the `IntStream` interface including the `range()` and `rangeClosed()` methods which can be used for replacing the simple `for` construct with exclusive and inclusive closing ranges.

Lets take a look.

``````
package info.java8;

import java.util.stream.IntStream;

/* IntStream ranges */
public class TestIntStreamB {

public static void main(String[] args) {

// Simple for
for (int i=1; i < 10; i++) {
printInt(i);
}

// range inclusive
System.out.println();
IntStream.rangeClosed(1, 9)
.forEach(TestIntStreamB::printInt);

// range exclusive
System.out.println();
IntStream.range(1, 10)
.forEach(TestIntStreamB::printInt);
}

private static void printInt(int i) {
System.out.print("i = : " + i +  ". ");
}
}

``````

Building and running the `TestIntStreamB` class produces the following output:

As you can see we get the same results from all three loops as we would expect.

Although limited to replacing the simple `for` construct when we want to loop incrementally and sequentially, you can see how simple the `range()` and `rangeClosed()` methods are compared to the simple `for` construct. Same results with much simpler, less error prone code.

### Taking Advantage of Numeric Streams Top

Well this is all great but lets see if we can take advantage of this new knowledge when we are using object type streams instead of primitive type streams.

We will be using the `Employee` class we created in the Introducing Streams lesson to test against for this purpose.

The following code snippet could be used to show the average age of all employes:

``````
/* Get average age of all staff */
double averageAge = Employee.listOfStaff().stream()
.map(Employee::getAge)
.reduce(0, Integer::sum);
System.out.println("Average age of staff is: "
+ averageAge / Employee.listOfStaff().size());

``````

This produces the required result of 43.2 but is quite verbose. The code also includes some unwanted boxing of the `Integer` object to an `int` primitive before summation which could have a big impact on performance if this was a large list, so not ideal.

We used the `reduce()` terminal operator, for the first time, which performs a reduction on the elements of this stream, using the provided identity, accumulation and combining functions

Lets try and simplify the above code/p>

``````
/* Get average age of all staff */
double averageAge = Employee.listOfStaff().stream()
.map(Employee::getAge)
.sum();
System.out.println("Average age of staff is: "
+ averageAge / Employee.listOfStaff().size());

``````

This doesn't even compile as the output from a map is `Stream<T>` which doesn't have a `sum()` method.

Luckily for us the developers of Java had the foresight to see this type of situation and introduced three stream interfaces for primitive numeric types, these being `IntStream`, `DoubleStream` and `LongStream`. Each have map methods that return a stream of the primitive type required.

Lets see this in action

``````
/* Get average age of all staff */
double averageAge = Employee.listOfStaff().stream()
.mapToDouble(Employee::getAge)
.sum();
System.out.println("Average age of staff is: "
+ averageAge / Employee.listOfStaff().size());

``````

This is still quite bloated but does produce the required result of 43.2.

Looking through the Java documentation for the `IntStream` interface I can see there is an `average()` method that returns an `OptionalDouble` object, so lets give that a whirl!

``````
/* Get average age of all staff */
OptionalDouble averageAge = Employee.listOfStaff().stream()
.mapToDouble(Employee::getAge)
.average();
System.out.println("Average age of staff is: " + averageAge.getAsDouble());

``````

Well we finally got there, this is a lot easier to read and more efficient.

We used the `mapToDouble()` intermediate operator, for the first time, which returns a `DoubleStream` consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element and the `.average()` terminal operator which returns an `OptionalDouble` describing the arithmetic mean of elements of this stream, or an empty optional if this stream is empty.

It is worth getting to know your way around the `IntStream`, `DoubleStream` and `LongStream` interfaces as the methods within them can be very useful for creating clean efficient code.

### Related Quiz

Streams Quiz 5 - Numeric Streams Quiz

## Lesson 5 Complete

In this lesson we looked at numeric streams and some of the operations associated with them.

## What's Next?

In the next lesson we take a final look at stream creation.