Java 8 introduced functional programming and the concept of streams and functional interfaces to back it. As the name suggests, Java 8 Stream can be thought of as a stream or source of data to operate on.
For this tutorial, we assume the reader to have an understanding of Java Optional and Functional Interface.
Java Stream helps us to reduce our lines of code significantly. For instance, suppose we have a List of marks:
List<Integer> listOfMarks = new ArrayList<>(); listOfMarks.add(90); listOfMarks.add(89); listOfMarks.add(98);
public double getAverageMarks(List<Integer> listOfMarks) { int totalMarks = 0; for(int marks : listOfMarks) totalMarks += marks; return (double)totalMarks/listOfMarks.size(); }
double avg = listOfMarks.stream().mapToInt(i -> i).average().getAsDouble();
Some of the most common ways to instantiate a stream involve:
java.util.stream package supports many operations over a Stream. An easy way to say open a stream over a given list of integers and print them would be:
Stream.of(1, 2, 3, 4).forEach(System.out::println);
We can also use an array to instantiate a stream:
Stream.of(new Integer[] {1, 2, 3, 4}).forEach(System.out::println);
Opening a stream say over a list of elements or any other Collection will make use of stream() method:
Stream<Integer> streamOfMarks = listOfMarks.stream();
The Stream.generate() method accepts a Supplier<T> which accepts an input source which acts as an infinite stream. The programmer is expected to specify the limit of the stream size:
Stream<String> streamGenerated = Stream.generate(() -> "programmerGirl").limit(50);
This method accepts the iteration logic to be used for instantiating a stream. Let’s look at an example:
Stream<Integer> iteratedStream = Stream.iterate(2, i -> i + 2).limit(50);
chars() method in String class can help us open a stream of characters:
IntStream streamOfChars = "programmerGirl".chars();
Intermediate operations in Stream are the ones that produce another Stream as an output. With this, we can chain multiple such methods.
There are innumerous operations supported by Streams. In this article, we’ll only cover the most commonly used operations – map() and filter().
As the name suggests, filter() method filters out the elements from our source stream based on the provided condition. The condition used to filter is provided in the form of a Predicate<T>:
listOfMarks.stream().filter(i -> i >= 90) .forEach(System.out::println); //only prints 90 and 98
map() operation helps us transform the elements in a Stream from one type to another. For example:
Stream<Integer> intStream = Stream.of("1", "2", "3").map(Integer::parseInt);
Some other common operations over Stream involves:
It returns the count() of elements present in our stream:
long count = Stream.of(1, 2, 3).count(); //outputs 3
It helps in iterating over the elements of our stream:
Stream.of(1, 2, 3).forEach(System.out::println);
It helps in performing some sort of reduction over a given stream. An easy example would be:
OptionalInt reducedValue = IntStream.rangeClosed(1, 5).reduce((i, j) -> i + j);
All of these methods have a boolean output and are used to match a specific condition:
boolean matched = Stream.iterate(1, i -> i+1).limit(100).anyMatch(n -> n==50); //true boolean noneMatched = Stream.iterate(1, i -> i+1).limit(100).noneMatch(n -> n==50); //false boolean allMatched = Stream.iterate(1, i -> i+1).limit(100).allMatch(n -> n > 0); //true
findFirst() returns the first element from the stream as an Optional. As soon as the first element is found, it stops any further processing:
int firstElement = Stream.iterate(1, i -> i+1).limit(100).findFirst().get();
The stream can be collected into a Collection or an Array. Let’s look at the approaches:
This method helps us to collect the output generated using a Stream. For example:
List<Integer> listOfEvenIntegers = Stream.iterate(1, i -> i+1).limit(100).filter(i -> i%2 == 0).collect(Collectors.toList());
To collect a Stream into an Array, we’ll use something like:
Integer[] arrayOfEvenIntegers = Stream.iterate(1, i -> i+1).limit(100).filter(i -> i%2 == 0).toArray(Integer[]::new);
In this tutorial, we got introduced to Java 8 Streams API. We looked at ways of instantiating a Stream followed by covering a few common operation over stream.
We also learned to recollect the output stream in a List or an array.