Stream API And Collectors (SE8)

Preface 

Knowledge about this part:

    Different Kind of Stream: squentially and parallel Streams.

    Stream Operations are either immediate and terminal.

    How to create Stream by many ways.

    Optimized Stream

    Process in deep of Stream

    Collector: convert Stream to List, Map, Set, customize Collectors, collector return single value.

    Sort on List or Stream.

    FlatMap: how to use flatmap.

    Reduce: how to use reduce(), compare with collector().

Start 

    Introduced in java 8, the Stream API is used to process collections of objects. A Stream is a se-quence of objects that supports various methods which can be pipelined to produce the desired result. 

Steam differ from collections in serverals ways:

    No storage. A stream is not a data structure that stores elements, instead, it conveys elements from a source such as a data structure, an array, a generator function, or an I/O channel, through a pipeline of computational operations.

    Functional in nature. An operation on a stream produces a result, but does not modify its source. For example, filtering a stream obtained from a collection produces a new stream without the filterd element,

    Laziness-seeking. Many stream operations, such as filtering, mapping or duplicate removal, can be implemented lazily, exposing oppotunities for opptimization. e.g in the illustrations bellow.

 The elements of a stream are only visited once during the life of the stream. Like Interator, a new stream must a generated to revisit the same elements of the source.

Now, we are learning how to work with java 8 streams and how to use the different kink of avaiable stream operarions. You will learn about the processing order and how the ordering of streams operations affect runtime performance.

Stream new instance from various ways:

1. From a Collection via the steam() and parallelStream() methods.

2. From an array via Arrays.Stream(Object[]).

3. From static factory methods on the stream classes such as Stream.of(Object[])IntStream.range(int min, int max), Stream.iterate(Object, UnaryOperator).

4. The lines of the file can be obtained from BufferedReader.lines().

5. Streams of file paths can be obtained from methods in Files.

6. Stream of random numbers can be obtained from random.ints()

Numberous other stream-bearing methods in the JDK, include BitSet.stream(), Pattern.splitAsStream(CharSequence) and JarFile.Stream.

 


 Now see Github: that to create Stream:

 https://github.com/nguyenthinhit996/sharefullcode/blob/java/Learn%20Java/NewFeatureSE8/src/featuresameple/streamapi/CreateStreams.java


Stream Work

 A Stream represent a sequece of elements and supports different kind of operations to perform computation upon those element.

Stream operations are either intermadiate or terminal. 

Imtermediate operations return a stream so we can chain multible Imtermediate without using semicolons. Map, Filter, Sorted is method of imtermediate.

 The figure in bellow use Imtermediate operations:


Github open source: 

https://github.com/nguyenthinhit996/sharefullcode/blob/java/Learn%20Java/NewFeatureSE8/src/featuresameple/streamapi/SteamImatermediateOperations.java

 

Terminal operations are either void or return non-strean result.

    Collect, forEach, reduce method is terminal. the example will update in the artcles bellow.


Recipe Sum(), Avarage(), ParseInt, Parse Double, Parse Long.



 Processing in deep

The imtermediate operations will only be excuted when a terminal operations is present. that figure bellow:




 Should put Map method behind Filter method to optimize, sorted methods is a special kind of intermediate operation. The figure illustration bellow:

Version 1 is not optimized:

    sort Function is sort all element of stream then to filter to map Function really run. it not optimized.  


 

Version 2 optimized:

    Filter funcion is runed that filter value corresponding condition of filter function then sort those value because The value of filter ouput only one so sort function not call yeh it really optimized.


Collectors

Collect is an extremly useful terminal operation to transform the element of the stream into a different kinds of result such as List, Map, Set. You can customize Collector of yourself by implement interface Collector <T,A,R> it very easy so you is assurance about it.

Data example of Stream for example in bellow:

List<Personz> persons =
    Arrays.asList(
    new Personz("Max", 18),
    new Personz("Peter", 23),
    new Personz("Pamela", 23),
    new Personz("David", 12));

 

Convert from Stream to List 

    streamToListSimple convert from stream to list. List personz continue use Map get name of person to Uppercase finally parse to list by Collect(Collectors.ToList).

 

Convert from Stream to List by toCollection()

List<String> result = givenList.stream()
  .collect(toCollection(LinkedList::new))


You can see its very simple to contruct a list from the elements of a stream. Need a set instread of list just use Collectors.ToSet(), see figure bellow:

Convert from Stream to Set

It merges two similar values of Stream is "Max" into one.


Convert from Stream to Map

A common database query might include a group by statement. It is possible to implement it with java but cumbersome and very verbose. In collector, those cumbersome is fixed see bellow illustration

Convert from Stream to Map use GroupBy

Map<age,List<Person>> parse stream to map group by follow age


Convert from Stream to Map use Partitioning collector

Partitioning is technically a special case of grouping. A predicate (function which return boolean value) is used to divide the stream into two groups. It returns a Map and its keys are boolean. So example bellow is divide age > 20 and remain.

 


Convert from Stream to Map use ToMap Function

 Function.identity() is just a shotcut for defining a function that accepts and returns the same value. 

In mathematics, an identity function, also called an identity relation or identity map or identity transformation, is a function that always returns the same value that was used as its argument – Wikipedia


Case duplicate key throw exception  java.lang.IllegalStateException 



That fixed it we use third argument in toMap function. if duplicate key it will use value of third argumet instead of value of second argument.


Collector returning a single value

An example of a collector which return a single value is couting() this count a number of elements in a stream. Other notable collectors in this group include:

Maxby(), Minby(), summingInt(). Using joinning() return String value split character customize.

 

 

Result Consolog

 


Custom Collectors

The collector interface defines a set of methods which are used during the reduction process. The following is the interface signnature with the five methods its declare.

 public interface Collector<T,A,R>{

    Supplier<A> supplier;

    Biconsumer<A, T> accumulator();

    Function<A, R> finisher();

    BinaryOperator<A> combiner();

    Set<Characteristics> characteristics();

}

T is the type of items in the steam to be collected.

A is the type of the accumulator

R is the type of the result returned by the collector.


Supplier 

The supplier() must return a function that creates an empty accumulator. This will repersent the result of the collection process when applied on an empty stream.


Accumulator

The job of the accumulator() is to return a function which performs redution operation. it accepts two arguments. First one being the mutable result container (accumulator) and the second one the stream element that should be folded into the result container.

 

Finisher 

The finisher() returns a function which performs the final transformation from the intermediate result container to the final reulst of type R. Often times the accumulator alreadly represents the final result, so the finisher can return the identity function.

 

Combiner

When is stream is collected in paralle the the combiner() method is used to return a funciton which knows how to merge to accumulator.

 

Characteristics

The characteristics() method returns an immutable set of characteristics which define the behavior of the collection. this is used to check which kind of optimizations can be done during the process. For example, if the contains Concurent then the collection process can be performed in paralle.

the Following: https://blog.indrek.io/articles/creating-a-collector-in-java-8/

 

Simple Example Customize Collector.

Now we want to transform all persons of the stream into single String value consisting all names in upper letters seperated by ?. We can create collector by Collectors.of(). We have to pass the four ingredients of a collector: a supplier, an accumulator, a compiler and a finisher.

 




[Supplier] create object StringJoiner -> [accumulator] Container (StringJoiner) + value of element of stream -> [combiner] not merge because not paralle perform -> [finisher] result is (StringJoiner) 

Note : Object "Max" had Removed before runed source again.

 

 

Advanced Example Customize Collector.

In exmaple previous Collector create by Collector.Of it easy but some cases advanced you can implement interface Collector<T,A,R> that use for create Collector.




User collector alreadly customize


IDENTITY_FINISH :Indicates that the finisher() function is the identity function and can be left out

UNORDERED: Indicates that the collection operation does not commit to preserving the encounter order of input elements.

Code Collector GitHub:

https://github.com/nguyenthinhit996/sharefullcode/tree/java/Learn%20Java/NewFeatureSE8/src/featuresameple/streamapi


Sort

    The sort is very more way, sort by implements Comparator (Non-generic Old Style), sort by implements Comparator(Generic), In java se8 has sort by functional interface this is illustration bellow code by function interface:



Result consolog:

GitHub: https://github.com/nguyenthinhit996/sharefullcode/blob/master/Learn%20Java/NewFeatureSE8/src/featuresameple/streamapi/SteamImatermediateOperations.java


FlatMap


    We've already learned how to transform the objects of a stream into another type by ulitizing the map operation. Map is kinda limited because every object can only be mapped to exactly one other object e.g get only one propertiese not get list object. If we want to transform one object into multite others or non at all, We use flatMap comes to the recue. The example use get list Student in ClassRoom by FlatMap

Relation of ClassRoom and Student class.


Use FlatMap Print list student


Result 



FlatMap is also avaiable for the Optional class introduced in Java 8. Optionals FlatMap operation returns an optional object another type. So it can utilized to prevent nasty Null checks.


 

Using that check Null



Reduce

    The reduction operation combines all element of the stream into a single result. In java 8 support three difference kind of Reduce methods. The first one reduces a stream of elements to exactly one element of the stream (all element -> one element).

The example get Person by max age:


The second reduce method accepts both an identity value and a BinaryOperation accumalator.  Identity has contruct new Person it use for start accumulator function this example bellow illustration aggregated age and name into one Object Person Identity inital before.


The third ruduce method accepts three arguments: an identity, a BiFunction accumulator and a combiner function of type BinaryOperator. Since the identity values type is not restricted to Person type it difference with identity in method first of reduce return one element of stream. see example bellow that view sum of age in stream List Person.

Difference Reduce and Collect 

     if you are somewhat familiar with streams, then you'll probably wonder why not use the reduce() method. Most of the time you can achive the same result. There are sematic difference. the reduce() method should be combine two values and return a new one value, meaning that reduction process should be immutable (silent not changes struct). Whereas the Collect() method is designed to mutable a container to accumulator the result it's supposed to produce.

(Reference following : https://blog.indrek.io/articles/creating-a-collector-in-java-8/)

 

Parallel Streams 

    Already understand how to create and perform with sequential stream then we will see how to create and perform with parallel stream. Let's go.

    Stream can be excuted in parallel to increase runtime performance on large amount of input elements. Parallel streams use a common ForkJoinPool avaiable via the static ForkJoinPook.commonPool() method. The size of the underlying thread-pool use up to higher depending-on the amount of avaiable physicall CPU cores.

 


On my machine the common pool is initialized with parallelism of 3 per default. This value can be increase or decrease by setting the following JVM paramater.

-Djava.util.concurrent.ForkJoinPool.common.parallelism=5

Can use parallelStream() to create a parallel stream of elements.



Result 



As you can see parallel stream utilizes all avaiable threads from the common ForkJoinPool for excuting the stream operations.  The result may differ in consecutive runs because the behavior which particular thread is actually used is non-deterministic.

    it can be start parallel stream with large elements input. but keep in mind that some parallel stream operation like Reduce, collect need additional computation (Combiner function) , it not necessary for squentially stream.


Summary Stream

    Different Kind of Stream: squentially and parallel Streams.

    Stream Operations are either immediate and terminal.

    How to create Stream by many ways.

    Optimized Stream

    Process in deep of Stream

    Collector: convert Stream to List, Map, Set, customize Collectors, collector return single value.

    FlatMap: how to use flatmap.

    Reduce: how to use reduce(), compare with collector().


OpenSource Of this section on github: 

https://github.com/nguyenthinhit996/sharefullcode/tree/java/Learn%20Java/NewFeatureSE8/src/featuresameple/streamapi


Finish 

 

    This section is non commercial mainly sharing and advance knowlage for java.This tutorials has referenced document from the list below if you has complain for license, i will remove all from internet. Thank you all everything.

 

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#package.description

https://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/

https://www.geeksforgeeks.org/stream-in-java/ 

https://blog.indrek.io/articles/creating-a-collector-in-java-8/

https://www.baeldung.com/java-8-collectors



0 comments :

Post a Comment

Cancel Reply

About Me

My photo
Tân An, Long An, Vietnam
Hello everyone, I love programming, I love making friends with people all over the world.