The following two tabs change content below.
Hi, I have written and developed this site to share my experience and ideas with other colleagues. I also started to prepare interview questions and answers for job seekers. I hope it will help you a lot.

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.

 

Download full source code

 

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));
 } 
}

BiFunction
BiFunction

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);
 } 
}

BiConsumer
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));
 
}
}

BiPredicateExample
BiPredicateExample

 

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

}
}

filter
filter

 

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));
 }
}

SpliteratorExample
SpliteratorExample

 

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();
 }
 });
 }
 }

SequentialParallelExample
SequentialParallelExample

 

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); 
 }
}

SortedStreamExample
SortedStreamExample

 

Download full source code

965 total views, 2 views today

2 thoughts on “Java stream API with example of Aggregate operations, Spliterators, Optional, BiConsumer, BiFunction etc”

Leave a Reply

Your email address will not be published. Required fields are marked *