Latest posts by khushvinder (see all)
- File upload using Spring Boot and Angularjs - January 1, 2018
- What is SOLID design principles in java? - November 30, 2017
- How to build Rest web services(API) using spring boot framework - November 20, 2017
Java stream API with examples
Stream is a feature in Java 8. Stream supporting Internal iteration which will provides several features such as sequential and parallel execution, filtering based on the given criteria, mapping etc.
Java 8 Stream support sequential as well as parallel processing, parallel processing can be very helpful in achieving high performance for large collections.
All the Java Stream API interfaces and classes are in the java.util.stream package. Since we can use primitive data types such as int, long in the collections using auto-boxing and these operations could take a lot of time, there are specific classes for primitive types – IntStream, LongStream and DoubleStream.
In details below are the key point of stream API:
Sequence of elements − A stream provides a set of elements of specific type in a sequential manner. A stream gets/computes elements on demand. It never stores the elements.
Source − Stream takes Collections, Arrays, or I/O resources as input source.
Aggregate operations − Stream supports aggregate operations like filter, map, limit, reduce, find, match, and so on.
Pipelining − Most of the stream operations return stream itself so that their result can be pipelined. These operations are called intermediate operations and their function is to take input, process them, and return output to the target. collect() method is a terminal operation which is normally present at the end of the pipelining operation to mark the end of the stream.
Automatic iterations − Stream operations do the iterations internally over the source elements provided, in contrast to Collections where explicit iteration is required.
Now thing is how to create stream object?
There are many ways to create a stream instance of different sources. Once created, the instance will not modify its source, therefore allowing the creation of multiple instances from a single source.
1.Empty Stream
The empty() method should be used to create empty stream:
Stream<String> streamEmpty = Stream.empty();
Its often the case that the empty() method is used upon creation to avoid returning null for streams with no element:
public Stream<String> streamOf(List<String> list) { return list == null || list.isEmpty() ? Stream.empty() : list.stream(); }
2. Stream of Array
Stream<String> streamOfArray = Stream.of("a", "b", "c");
They can also be created out of an existing array or of a part of an array:
String[] arr = new String[]{"a", "b", "c"}; Stream<String> streamOfArrayFull = Arrays.stream(arr); Stream<String> streamOfArrayPart = Arrays.stream(arr, 1, 3);
3. Stream of Collection
Stream can also be created of any type of Collection (Collection, List, Set):
Collection<String> collection = Arrays.asList("a", "b", "c"); Stream<String> streamOfCollection = collection.stream();
4. Stream.generate()
if you want to repeat a element into stream till the given length the use below code:
Stream<String> streamGenerated = Stream.generate(() -> "element").limit(10);
Note: we can also achieve using Stream.iterate()
Stream<Integer> streamIterated = Stream.iterate(40, n -> n + 2).limit(20);
5. Stream.builder()
If you want to add more element during the stream creating then you can you below code:
Stream<String> streamBuilder = Stream.<String>builder().add("a").add("b").add("c").build();
Functional Interfaces in Stream API
In the stream we have four type of functional interface as mention below:
1. BiFunction
java.util.function.BiFunction is a functional interface. BiFunction accepts two arguments and returns a value. While declaring BiFunction we need to tell what type of argument will be passed and what will be return type. We can apply our business logic with those two values and return the result. BiFunction has function method as apply(T t, U u) which accepts two argument.
BiFunctionExample.java
package com.kpblogs.java_stream_api; import java.util.function.BiFunction; public class BiFunctionExample { public static void main(String[] args) { BiFunction<Integer, Integer, String> biFunction = (num1, num2) -> "Output:" +(num1 + num2); System.out.println(biFunction.apply(10,25)); } }

2. BiConsumer
java.util.function.BiConsumer is a another functional interface. BiConsumer does not return value. It accepts two parameter as an argument. BiConsumer functional method is accept(Object, Object). This methods performs the operation defined by BiConsumer.
BiConsumerExample.java
package com.kpblogs.java_stream_api; import java.util.HashMap; import java.util.Map; import java.util.function.BiConsumer; public class BiConsumerExample { public static void main(String[] args) { Map<Integer,String> map = new HashMap<>(); map.put(1, "A"); map.put(2, "B"); map.put(3, "C"); map.put(4, "D"); BiConsumer<Integer,String> biConsumer = (key,value) -> System.out.println("Key:"+ key+" Value:"+ value); map.forEach(biConsumer); } }

3. BiPredicate
It represents a predicate against which elements of the stream are tested. This is used to filter elements from the java stream. Just like Function, there are primitive specific interfaces for int, long and double.
Some of the Stream methods where Predicate or BiPredicate specializations are used are:
BiPredicateExample.java
– Stream<T> filter(Predicate<? super T> predicate)
– boolean anyMatch(Predicate<? super T> predicate)
– boolean allMatch(Predicate<? super T> predicate)
– boolean noneMatch(Predicate<? super T> predicate)
package com.kpblogs.java_stream_api; import java.util.stream.Stream; public class BiPredicateExample { public static void main(String[] args) { Stream<Integer> numbers4 = Stream.of(1,2,3,4,5,12); System.out.println("Stream contains all elements less than 10? "+numbers4.allMatch(i -> i<10)); Stream<Integer> numbers5 = Stream.of(1,2,3,4,5,1); System.out.println("Stream contains all elements less than 10? "+numbers5.allMatch(i -> i<10)); } }

4. Supplier: Supplier represent an operation through which we can generate new values in the stream. Some of the methods in Stream that takes Supplier argument are:
public static<T> Stream<T> generate(Supplier<T> s) <R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner)
java.util.Optional Class
It is used to check a value is is there or not. Now no more too many null checks and NullPointerException. Like Collections and arrays, it is also a Container to hold at most one value. Let us explore this new construct with some useful examples.
Advantages of Optional class:
-Null checks are not required.
-No more NullPointerException at run-time.
-No more Boiler plate code
Now we are developing few example to explain the use of Optional Class
Creating Optional Objects: creating empty object
Optional<String> empty = Optional.empty();
If we have to check the value then there is function isPresent() like below:
Optional<String> optional = Optional.empty(); System.out.println(optional.isPresent()); //output will be false
for comparision we can use ifPresent like below:
Optional<String> optional = Optional.empty(); optional.ifPresent(name -> System.out.println(name)); //Nothing will be in output
another example of ifPresent
Optional<String> optional = Optional.of("kpblogs"); optional.ifPresent(name -> System.out.println(name)); //kpblogs will be in output
Few more methods are:
-Optional<T> reduce(BinaryOperator<T> accumulator)
-Optional<T> min(Comparator<? super T> comparator)
-Optional<T> max(Comparator<? super T> comparator)
-Optional<T> findAny()
-Optional<T> findFirst()
Filter, Map and FlatMap
package com.kpblogs.java_stream_api; import java.util.Optional; public class OptionalClassExample { public static void main(String[] args) { //Map and Flat Map Optional<String> blog = Optional.of("kpblogs"); System.out.println("Map :: " + blog.map(blogs -> blog.map(String::toUpperCase))); System.out.println("Flat Map :: " + blog.flatMap(blogs -> blog.map(String::toUpperCase))); //Filter System.out.println(blog.filter(g -> g.equals("kp"))); //Optional.empty System.out.println(blog.filter(g -> g.equalsIgnoreCase("kpblogs"))); //Optional[kpblogs] System.out.println(blog.filter(g -> g.equalsIgnoreCase("khushvinder"))); //Optional.empty } }

Spliterators
Like other Iterators, are for traversing the elements of a source. A source can be a Collection, an IO channel or a generator function.
It is included in JDK 8 for support of efficient parallel traversal(parallel programming) in addition to sequential traversal.
However, you can use Spliterator even if you won’t be using parallel execution. One reason you might want to do so is because it combines the hasNext and next operations into one method.
package com.kpblogs.java_stream_api; import java.util.ArrayList; import java.util.Collection; import java.util.Spliterator; import java.util.stream.Stream; public class SpliteratorExample { public static void main(String[] args) { Collection<Integer> al = new ArrayList<Integer>(); al.add(1); al.add(2); al.add(-3); // Obtain a Stream to the array list. Stream<Integer> str = al.stream(); // getting Spliterator object on al Spliterator<Integer> splitr1 = str.spliterator(); // estimateSize method System.out.println("estimate size : " + splitr1.estimateSize()); // getExactSizeIfKnown method System.out.println("exact size : " + splitr1.getExactSizeIfKnown()); // hasCharacteristics and characteristics method System.out.println(splitr1.hasCharacteristics(splitr1.characteristics())); System.out.println("Content of arraylist :"); // forEachRemaining method splitr1.forEachRemaining((n) -> System.out.println(n)); } }

Sequential vs Parallel streams
Parallel streams divide the provided task into many and run them in different threads, utilizing multiple cores of the computer. On the other hand sequential streams work just like for-loop using a single core.
The tasks provided to the streams are typically the iterative operations performed on the elements of a collection or array or from other dynamic sources. Parallel execution of streams run multiple iterations simultaneously in different available cores.
Note: In parallel execution, if number of tasks are more than available cores at a given time, the remaining tasks are queued waiting for currently running task to finish.
package com.kpblogs.java_stream_api; import java.time.LocalTime; import java.util.Arrays; import java.util.stream.Stream; public class SequentialParallelExample { public static void main(String[] args) { String[] strings = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}; System.out.println("-------\nRunning sequential\n-------"); runStream(Arrays.stream(strings).sequential()); System.out.println("-------\nRunning parallel\n-------"); runStream(Arrays.stream(strings).parallel()); } public static void runStream (Stream<String> stream) { stream.forEach(s -> { System.out.println(LocalTime.now() + " - value: " + s + " - thread: " + Thread.currentThread().getName()); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } }); } }

Stream sorted()
package com.kpblogs.java_stream_api; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class SortedStreamExample { public static void main(String[] args) { Stream<String> names2 = Stream.of("a", "b", "ef", "9810093311"); List<String> reverseSorted = names2.sorted(Comparator.reverseOrder()).collect(Collectors.toList()); System.out.println(reverseSorted); Stream<String> names3 = Stream.of("khushvinder", "pal", "kpblogs", "9810093311"); List<String> naturalSorted = names3.sorted().collect(Collectors.toList()); System.out.println(naturalSorted); } }

687 total views, 1 views today
Nice post sir.. thanks for sharing
Thank you Anil!!