Java 8 Array to Stream Example
1. Introduction
Official javadoc of java.util.stream.Stream
states that it is “A sequence of elements supporting sequential and parallel aggregate operations”. And such every Stream is backed by a source which would provide the Stream with its “sequence of elements”. In Java, like most other programming languages, sequence of elements is generally provided via two constructs: (i) the java.util.Collection
instances and (ii) the classical array.
In this post we are concerned with arrays and see how Streams can further make array processing easier and efficient. In fact the Stream documentation explicitly mention that arrays are valid source candidates for supplying Stream
its sequence of elements: “A stream pipeline consists of a source (which might be an array, a collection, a generator function, an I/O channel, etc)”. We would see all the standard filter-map-reduce operations work exactly the same way as with Collection instances!
2. Creating Streams out of Arrays
The simplest, effective way of easily creating Stream out of an array is to use one of the several overloaded static factory methods from java.util.Arrays
class. There are basically two flavors of factory methods: firstly, there are those methods which return Stream backed by primitive data types like int, float etc, and then there are those which return Stream backed by reference (of object) types. In the following sections we would see both these flavors in practice
2.1 Streams from primitive data arrays
Lets say we have an integer array of age of students in a class:
Instantiating an array of ints
int[] classAge = new int[]{21,25,27,24,26};
Then to seek an Stream from the above array, all we need to say is,
Creating Stream out of array of ints
IntStream ageStream = Arrays.stream(classAge);
Notice the return type of the factory method, it is java.util.stream.IntStream and not java.util.stream.Stream! Well, IntStream is a specialized form of Stream interface which deals specifically with sequence of primitive int type elements and as such it reduces the overhead of boxing-unboxing to and from java.lang.Integer objects.
Once we have IntStream in hand, all standard Stream operations can be applied as is. Consider some of the many operations that could be applied.
Filter operation, we want only even numbered ages:
Filter Operation
IntStream evenAges = ageStream.filter(age -> age %2 == 0);
Map Operation, we double the age of each student:
Map Operation
IntStream doubleAges = evenAges.map(age -> age*2);
Finally, we do an aggregating/reducing operation on the overall Stream:
Aggregating Operation
int sum = doubleAges.sum();
Here is the complete example source code:
Streams from primitive data arrays
package arraytostream; import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.IntStream; public class Java8ArrayToStreamExample { public static void main(String[] args) { int[] classAge = new int[]{21,25,27,24,26}; IntStream ageStream = Arrays.stream(classAge); //filter operation IntStream evenAges = ageStream.filter(age -> age %2 == 0); //map operation IntStream doubleAges = evenAges.map(age -> age*2); //aggregate operation int sum = doubleAges.sum(); System.out.println(sum); } }
2.2 Stream from array of object references
We just saw how Stream backed by primitive Java data types can be created and processed. Similarly, Streams can be culled out of arrays of object instances as well. We will slightly modify the semantics of the above example; now we would encapsulate the age of each student in an Student object and do similar operations as we did before!
Following is our Student class:
Student.java
package arraytostream; public class Student { String name; int age; public Student (String name, int age){ this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
Like before we will initialize an array of students:
Instantiating array of Student instances
Student [] studArray = new Student[] {new Student("Mohammad", 30), new Student("Nawazish", 31), new Student("khan", 32) };
After this, we can again use factory method from Arrays class to have a Stream of Student!
Creating Stream backed by array of Student instances
//Streams backed by array of Students Stream studStream = Arrays.stream(studArray);
Notice unlike before, this time we are having an array of objects (not primitives), and hence we do not have the primitive xxxStream
returned by the static factory method, rather this returns the generic Stream
type.
Once we have the Stream of Student, we can have all standard Stream operation done; for instance we will do filter operation in the following code:
Filter Operation
//Filter operation; only those students with even numbered age Stream evenAgedStudent = studStream.filter(student-> student.getAge()%2 == 0);
Similarly we may also perform mapping operations:
Map Operation
//Map each student's age by half Stream halfAge = evenAgedStudent.map(student -> { return new Student(student.getName(), student.getAge()*2); });
Following is the complete source code:
Stream from array of object references
package arraytostream; import java.util.Arrays; import java.util.stream.Stream; public class Java8ArrayRefToStreamExample { public static void main(String[] args) { Student [] studArray = new Student[] {new Student("Mohammad", 30), new Student("Nawazish", 31), new Student("khan", 32) }; //Streams backed by array of Students Stream studStream = Arrays.stream(studArray); //Filter operation; only those students with even numbered age Stream evenAgedStudent = studStream.filter(student-> student.getAge()%2 == 0); //Map each student's age by half Stream halfAge = evenAgedStudent.map(student -> { return new Student(student.getName(), student.getAge()*2); }); halfAge.forEach(student-> System.out.println(student.getName()+" :"+student.getAge())); } }
3. Conclusion
This example was about backing Streams from an underlying array as source. We saw how easy this is especially when we have library class like Arrays with its static factory method. Once a Stream instance is created from an underlying array source, further Stream operations remains the same.
I am getting error for Stream functions on Non-primitive array types. For stream functions, object has to convert to Student, as below :-
Student[] studArray = new Student[] { new Student(“Mohammad”, 30), new Student(“Nawazish”, 31),
new Student(“khan”, 32) };
Stream studStream = Arrays.stream(studArray);
Stream evenAgedStudent = studStream.filter(student -> ((Student) student).getAge() % 2 == 0);
Please suggest.