Java Streams API - Process set of elements

A Stream is a series of objects. Source of a stream is an Array, Collection, or Other I/O source. A Stream does not store data, it does only intermediate operations.

It can filter and manipulate the elements of its source. Streams are lazy, the source and intermediate operations do nothing until objects are needed by the terminal operation.

Steams APIs are contained by java.util.stream package. 



A water filter is the best example of streams.   It processes the water stream.  It has multiple filters that work one after another.  Filters do purification, reverse osmosis, refinement of water, and produce drinking water.  The water filter does not store the water it simply processes the water stream.

Getting Started 


1. Create a Stream and print all elements 

Let's create a stream from a collection and print all its elements. 

The following example creates a Stream from the list collection and prints all elements of the collection using its forEach method.

List<String> items = Arrays.asList("One", "Two", "Three", "Three", "Four");

//create stream
Stream<String> stream = items.stream();

// Print all elements from stream
stream.forEach(e -> {
System.out.println(e);
});

2.  Sort the elements and then print 

Stream elements can be sorted using sorted() method.

The following example will create a stream, sort its elements using sorted() method, and then print all elements.

items.stream().sorted().forEach(e -> {
System.out.println(e);
});

3.  Convert each element into UPPER CASE then print

Stream elements can be modified using map() method.

The following example will create a stream, convert each element into the upper-case using its map() method, and then print all elements.

items.stream().map(e -> e.toUpperCase()).forEach(e -> {
System.out.println(e);
});

4.  Filter elements starting with T character and  print

Stream elements can be filtered using filter() method. 

The following example will filter elements starting with T character using filter() method, convert them into upper case, and then print all elements.

items.stream().filter(e -> e.startsWith("T")).map(e -> e.toUpperCase()).forEach(e -> {
System.out.println(e);
});


5.  Remove duplicate elements 

Stream can remove its duplicate elements using distinct() method. 

The following example will filter elements, remove duplicate elements,  convert elements to upper case,  then print all elements.

items.stream().filter(e -> e.startsWith("T")).distinct().map(e -> e.toUpperCase()).forEach(e -> {
System.out.println(e);
});

6.  All together 

The following example will filter elements, remove duplicate elements,  convert elements to upper case,  sort elements then print all elements.

items.stream().filter(e -> e.startsWith("T")).distinct().map(e -> e.toUpperCase()).sorted().forEach(e -> {
System.out.println(e);
});

7. Get collection from Stream 

You can get processed elements from Stream into a collection using collect() method.

List<String> l = items.stream().filter(e -> e.startsWith("T")).distinct().map(e -> e.toUpperCase()).sorted().collect(Collectors.toList());

Streams vs Collections

Stream and Collection  look similar but there are major differences between both:

 # Stream                                                 Collection                                         
 1It does not store data    It stores data         
 2It is read-onlyIt is read and write both     
 3It can only be read once It can be read multiple times
 4Elements can not be directly accessed Elements can be directly accessed 
i = list.get(0)


Stream Sources 

A stream can be created from arrays, collection, files, and other I/O sources.




1. Collections/ Arrays 

List collection, Set collections, and arrays are the common sources of the stream. Map can not be directly used as a source.

String[] a = { "One", "Two", "Three", "Four"};
Stream<String> aStream = Arrays.stream(a);

List<String> l = Arrays.asList("One", "Two", "Three", "Four");
Stream<String> lStream = l.stream();

2. I/O

Data from File and  Network can be used as a source to the stream.

Stream<String> fiileData = Files.lines(Path.of("data.txt"));

3. Generators

A Stream can be generated from a function that returns elements for the stream.

For example in this example stream is created from random.nextInt() method.  After creating stream we print 5 random numbers.
Random random = new Random();
Stream<Integer> randomNumbers = Stream.generate(random::nextInt);
randomNumbers.limit(5).forEach(System.out::println);
Same can be done by Math.random() method:
Stream<Double> randomNumbers = Stream.generate(Math::random);
Operations 



Intermediate operations 

An Intermediate Operation transforms one stream into another stream.

Stream methods filter(), map(), distinct(), sorted() etc, perform intermediate operations, and produce another stream.

List<String> items = Arrays.asList("One", "Two", "Three", "Three", "Four");
Stream<String> stream = items.stream();
items.stream().sorted();
items.stream().map(e -> e.toUpperCase());
items.stream().filter(e -> e.startsWith("T"));
items.stream().distinct();
Intermediate operations are 
  1. map() -It maps a function to a stream and changes elements of the stream
  2. filter() - It filters element of the stream 
  3. distinct() - It removes duplicate elements from the stream
  4. sorted() - It sortes elements of the stream 
  5. limit() - It limits and returns the stream according to the given maxSize parameter
  6. skip() - It skips the given N elements of the stream  

Channing intermediate operations 

Channing makes Stream powerful. The output of one stream can be an input of another stream it is called Channing. 

You can chain multiple operations on stream and produce the desired result using the least code.

For example, the following code applies Channing operations filter, distinct, map, sort, and finally prints all elements of steam in a single line of code.
items.stream().filter(e -> e.startsWith("T")).distinct().map(e -> e.toUpperCase()).sorted();

Terminal stream operations

Streams are lazy,  that means sources and intermediate operations do not do any work until a terminal is executed.

List<String> items = Arrays.asList("One", "Two", "Three", "Three", "Four");
Stream<String> stream = items.stream();
items = items.stream().filter(e -> e.startsWith("T")).distinct().map(e -> e.toUpperCase()).sorted();
items.forEach(e -> {
System.out.println(e);

});
In the above example filter, distinct, map, and sorted intermediate operations will not be executed until the terminal operation foreach() method is called. 

Terminal operations are 
  1. collect() - It converts an stream into collection
  2. toArray() - It converts a stream into array
  3. count() -It returns the count of the elements in the stream
  4. reduce() - It reduces the elements of the stream according to the given identity value. 
  5. min() - It  returns the minimum element of the stream according to the given comparator
  6. max() - It  returns the maximum element of the stream according to the given comparator
  7. anyMatch() - It will return any matched element according to the matched predicate. if the stream is empty then return false
  8. allMatch() -It will return all the matched elements from a stream. returns true if the stream is empty.
  9. noneMatch() - It returns the matched elements of the predicate. returns true if the stream is empty
  10. findAny() - It returns an optional describing some elements of the stream
  11. findFirst() -  It returns the first elements of the stream.


Statistical Operations 



You can performer max, min, average statistical operation on integer or double stream.

Classes IntSummaryStatistics and DoubleSummaryStatistics are used to get integer and double value statistical operations.

Methods mapToInt() and mapToDouble() are used to convert stream elements into integers or double values before applying the statistical operations.

Following example will apply statistical operations on marks and account balance:

List<Integer> marks = Arrays.asList(80, 90, 75, 50, 45, 95, 75);
IntSummaryStatistics mStats = marks.stream().mapToInt(x -> x).summaryStatistics();
System.out.println("## Marks statistics ##");
System.out.println("Max Marks: " + mStats.getMax());
System.out.println("Min Matrks: " + mStats.getMin());
System.out.println("Average Marks:" + mStats.getAverage());
System.out.println("Sum : " + mStats.getSum());
System.out.println();

List<Double> accountBalance = Arrays.asList(10000.89, 20000.77, 5000.66, 5500.55, 7000.88, 30000.99, 50000.00);
DoubleSummaryStatistics aStats = accountBalance.stream().mapToDouble(x -> x).summaryStatistics();
System.out.println("## Balance statistics ## ");
System.out.println("Max Balance: " + aStats.getMax());
System.out.println("Min Balance: " + aStats.getMin());
System.out.println("Average Balance:" + aStats.getAverage());
System.out.println("Sum : " + aStats.getSum());

Real-World Example 

Let's have  Lucky Draw Contest in which contestants have to send SMS.  We will select random 3 winners from received SMSs 

We will follow the following procedure to select 3 winners:





Let's have data 

class Contestant {
public String phone = null;
public Contestant(String n, String p) {
name = n;
phone = p;
}
}
ArrayList<Contestant> list = new ArrayList<Contestant>();
list.add(new Contestant("Ram", "9912345678"));
list.add(new Contestant("Shyam", "9912342222"));
list.add(new Contestant("Ajay", "9912345770"));
list.add(new Contestant("Vijay", "9912345678"));
list.add(new Contestant("Jay", "9912345888"));
list.add(new Contestant("Pappu", "9912345111"));
list.add(new Contestant("InvalidNO", "11"));

1. Get the phone numbers 

 list.stream().map(e -> e.phone)

2. Get valid phone numbers 

list.stream().map(e -> e.phone).filter(e -> e.length() == 10)

3. Remove duplicate phone numbers 

list.stream().map(e -> e.phone).filter(e -> e.length() == 10).distinct()

4. Shuffle Phone numbers 

list.stream().map(e -> e.phone).filter(e -> e.length() == 10).distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), e -> {
Collections.shuffle(e);
return e.stream();
}))

5. Get 3 Winners 

list.stream().map(e -> e.phone).filter(e -> e.length() == 10).distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), e -> {
Collections.shuffle(e);
return e.stream();
})).limit(3)

6. Display winners 

list.stream().map(e -> e.phone).filter(e -> e.length() == 10).distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), e -> {
Collections.shuffle(e);
return e.stream();
})).limit(3).forEach(e -> System.out.println(e));

WOW !!! Its very simple !! 


Example Source Code

Find source code at GIT 


Also Watch:

► Deploy Angular build on Tomcat or WAMP server - https://www.youtube.com/watch?v=0Gvx7...  
► SpringBoot Hibernate Integration - https://www.youtube.com/watch?v=IcSyY...  
► Spring Boot – Create RESTful Web Service - https://www.youtube.com/watch?v=QcoB0...  
► Angular app using REST API (Part 3) - https://www.youtube.com/watch?v=nthgO...  
► Test Public REST API - https://www.youtube.com/watch?v=SUE90...  
► Angular First Project (Part-2) - https://www.youtube.com/watch?v=ZySHh...  
► Angular First Project (Part-2) - https://www.youtube.com/watch?v=Y9aSJ...  
► First Python Program - https://www.youtube.com/watch?v=w_Z6l...  

FOLLOW US ON ALL OTHER SOCIAL PLATFORMS!

►YOUTUBE - https://www.youtube.com/sunilos  
►LINKEDIN - https://www.linkedin.com/company/rays...  
►GITHUB - https://github.com/sunilos  

►FACEBOOK - https://www.facebook.com/sunilopensou... 

►URL - www.RaysTec.com, www.SunilOS.com







Comments

  1. Good Evening Sir,
    Does it create any impact on execution time if we change the sequence of filter->map()->reduce on any raw list(source)?

    Thank you for the content sharing sir.

    ReplyDelete
    Replies
    1. Yes, it will, you should execute operations in the order that number of elements will be reduced for next operation. Elimination filter operations should always come first.

      Delete
  2. Thank you because you have been willing to share information with us. We will always appreciate all you have done here because I know you are very concerned with us. Whole house water filtration

    ReplyDelete

Post a Comment

Popular posts from this blog

Lambda Expressions

Java 8 Vs Java 9