What is a Stream in Java 8?
Another Java 8 important feature, it can be defined as a pipeline through which a collection of objects and primitive data can be streamed through and a set of operations are performed over each object.
In other words, It is used to process a collection of objects. It streams over a sequence of objects from a source ( collection of objects or primitive types ), perform intermediate operations on each and every element of that source and provide the final outcome.
A stream can be accompanied by zero or more intermediate operations.
Points to remember:
– It converts the normal list to a stream
– It is used to process data using filter, map and other, the final output can be collected to form a list
– It doesn’t manipulate original data, instead creates a new stream
– It provides various stream operation such as map, filter and more
– An element in a stream is always traversed exactly once.
– It does the stream lazily as it doesn’t traverse until the terminal operation doesn’t get executed
-It forms a pipeline where intermediate operations and terminal operations are chained together
There are two ways in Collection interface to produce a Stream:
– stream() -> It returns a sequential stream
– parallelStream() -> Returns a parallel stream. It utilizes the multiple cores of the computer by creating multiple threads to form sub-streams and assigns them given tasks which execute in parallel.
A stream can be split into two operations. An intermediate operation where all the manipulation is done and a terminal which produces the end result.
Stream Source or Create a Stream
A source might represent an array, collection and other. Another way is, to create a stream and do the further opertion on that particular stream.
Create Streams
- Stream.of
A static method that returns a squence of ordered stream.
Stream.of(val1,val2 .. ......)
Code Example :
public class CreateStreams { public static void main(String[] args) { // Creating Stream of Characters Stream<Character> characterStream = Stream.of('P', 'R', 'O', 'G', 'R', 'A', 'M', 'M', 'E', 'R', 'B', 'A', 'Y'); // Now Printing it as a word characterStream.forEach(singleCharacter -> System.out.print(singleCharacter)); } }
Output:
PROGRAMMERBAY
One can also create Stream of array with Stream.of() method.
For example:
public class CreateStreams { public static void main(String[] args) { String[] stringArr = new String[]{"This", "is", "Example", "of", "Stream"}; // Creating Stream of Array Stream<String> arrayStream = Stream.of(stringArr); arrayStream.forEach(singleString -> System.out.print(singleString + " ")); } }
Output:
This is Example of Stream
- List.stream()
In this, a list acts like stream and all the operations are done, just as normal stream.
Code example :
public class CreateStreams { public static void main(String[] args) { List<String> stringList = new ArrayList<>(); stringList.add("A"); stringList.add("list"); stringList.add("example"); stringList.add("with"); stringList.add("Stream"); stringList.forEach(singleString -> System.out.print(singleString + " ")); } }
Output:
A list example with Stream
Intermediate Operations
An intermediate operation is an operation that always returns a new stream.
Filter()
– It allows us to put conditional checks and filter out specific element or data from the source data in form of a new stream.
– It uses predicate as an argument which always returns a boolean type.
Syntax:
filter(Predicate<? super T> predicate)
Map()
– It allows us to manipulate the data source or process the data and get the result from it.
– It maps each element to its corresponding result and provides a new stream.
– It accepts Function as an argument which processes a given input to provide the result.
Syntax:
map(Function<? super T,? extends R> mapper)
Sorted
-It sorts a list of elements as per natural order.
-However, one can achieve custom behaviour using Comparator.
Code Example :
public class CreateStreams { public static void main(String[] args) { List<Integer> integerList = new ArrayList<>(); integerList.add(5); integerList.add(2); integerList.add(12); integerList.add(1); integerList.add(45); integerList.add(9); integerList.stream().sorted().forEach(System.out::println); } }
Output:
1 2 5 9 12 45
Terminal Operations
A terminal operation is an operation that returns non-stream values such as Optional, object, collection and more.
Reduce()
A reduce method performs a certain operation on each element of a given list and produces a single output value. In simple words, it reduces a list to a single output.
-It takes two arguments, first is identity and the second one is Accumulator.
Identity: It resembles the initial value of the reduction operation and acts as a default output if no data exist in the given list.
Accumulator: It is itself a function that takes two parameters, the first one is partial output and the second argument represents the next element of the list.
Code example :
public class CreateStreams { public static void main(String[] args) { List<Integer> integerList = new ArrayList<>(); integerList.add(5); integerList.add(5); integerList.add(15); Integer sum = integerList.stream().reduce(0,(initialVal, nextElm) -> initialVal + nextElm ); System.out.println("Sum : "+sum); } }
Output :
Sum : 25
Collect
-It is used to translate a stream into a list.
-It simply consolidates all the processed result and returns a list
Syntax:
collect(Collector<? super T,A,R> collector)
Collecting stream data as an array :
toArray() is used to get an array as output after performing intermediate operations.
Code example:
public class CreateStreams { public static void main(String[] args) { List<Integer> integerList = new ArrayList<>(); integerList.add(5); integerList.add(10); integerList.add(12); integerList.add(15); integerList.add(21); integerList.add(24); Integer[] intArr = integerList.stream().filter(singleElement -> (singleElement % 5 == 0)).toArray(Integer[]::new); for (Integer element : intArr) { System.out.println("Multiples of 5 : " + element); } } }
Output:
Multiples of 5 : 5 Multiples of 5 : 10 Multiples of 5 : 15
Collecting stream data as a list :
collect(Collectors.toList()) is used to get a list as output after performing intermediate operations.
Code example:
public class CreateStreams { public static void main(String[] args) { List<Integer> integerList = new ArrayList<>(); integerList.add(5); integerList.add(10); integerList.add(12); integerList.add(15); integerList.add(21); integerList.add(24); List<Integer> intList = integerList.stream().filter(singleElement -> (singleElement % 5 == 0)).collect(Collectors.toList()); for (Integer element : intList) { System.out.println("Multiples of 5 : " + element); } } }
Collecting stream data as a Map:
collect(Collectors.toMap() is used to get a Map as output after performing intermediate operations.
Code example:
public class CreateStreams { public static void main(String[] args) { List<Integer> integerList = new ArrayList<>(); integerList.add(5); integerList.add(10); integerList.add(12); integerList.add(15); integerList.add(21); integerList.add(24); Map<Integer,Integer> intMap = integerList.stream().filter(singleElement -> (singleElement % 5 == 0)).collect(Collectors.toMap(key -> key / 5 , value -> value)); System.out.println("Map " + intMap); } }
Output:
Map {1=5, 2=10, 3=15}
forEach
-Loop through each element of the given stream. It is a new feature provided in Java 8.
Syntax
forEach(Consumer<? super T> action)
Filter and forEach program example:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class StreamExample { public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(5,10,50,15,30,40)); list.stream().filter(singleEelement -> (singleEelement > 30)).forEach(element -> System.out.println("All value greater than 30 :- "+element)); } }
Output:
All value greater than 30 :-50 All value greater than 30 :-40
Explanation:
Above code, filter method is creating a stream in which only values that are greater than 30 is present, then after, simply printing it over the screen using forEach() method.
Map and Collect program example
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StreamExample { public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(5,10,50,15,30,40)); List newList = list.stream().map(singleEelement -> singleEelement+5).collect(Collectors.toList()); newList.forEach(element -> System.out.println(element)); } }
Output:
10 15 55 20 35 45
Explanation:
Above code, map method is creating a stream in which each element is incremented by 5 are present, then after, simply converting it to list.