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:
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:
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:
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:
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:
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 :
About Me

- Peter
- Tân An, Long An, Vietnam
- Hello everyone, I love programming, I love making friends with people all over the world.
Contact
Popular Posts
-
The one of Design Pattern Series, this is factory design for createnal pattern. Please read in the linked document. Link document: https:...
-
youtube tutorial: https://www.youtube.com/watch?v=IEf1KAcK6A8 1 let and scope, 2 const, 3 array function 4 default value 5 Object iteral ext...
-
1 Copy Object in java Use = for immutable class ex: Integer , String or Wrapper classes Object Use Contructor has paramater copy, ObjectA...
-
JPA find() & getReference() in javax.persistence.EntityManager * find (): always call select from DB Use for select one entity from DB...
-
Preface Trong java có 3 kiểu so sánh đặc trưng như sau: + Sử dụng toán tử == : return Boolean Primitive thì so sánh giá trị thực, Reference ...
-
Persistence Context has two implemnet is JPA EntityManage and Hiberbate Session Example use Session of hiberate has exist github you can vi...
-
1 check Null and Undefined And primative datatype if(object){ // object is not null, undefined, 0, '', false. but it can empty({})...
-
1) CRUD có thể sử dung find Compositekey hoặc findBy compositeket + column in composite 2) CRUD findBy column And column 3 Not LazyLoa...
-
This post use language vietnames is, the future is will introduce english version. The clean code for java also application for the others. ...
-
Parse LocalDateTime to String to pattern year : yyyy || 2021 month of year: M / MMM / MMMM || 06 / Jun / June da...
Post a Comment