Pages

Friday, August 14, 2020

A Guide to Streams in Java 8: In-Depth Tutorial With Examples

1. Stream API Overview

In this tutorial, We'll take a look at an in-depth tutorial with examples on Java 8 Stream API.

Java 8 introduced a new API which is called as Stream. This API supports processing the large data sets in a sequential and parallel model.
When we see the code that looks to the SQL query database.

Before that, you can take a look at the Java 8 Lambda Expression Rules to write the errorless code.

Java 8 Stream API Introduction


we'll learn about java 8 in the aspect of the following.


  • Impact of Multi-Core CPU
  • Anonymous Inner classes
  • Stream Pipe Line
  • Functional Interfaces
  • How java 8 code looks with Examples
Stream API provides a package java.util.stream. This API provides several methods to iterate over a stream. This iterator can be called as New Fancy Iterator.
These methods can be used as a chain of the pipeline with complex logic similar to the UNIX pipeline command as below.

grep 'Exception' application.log | grep -V 'Server Exception' | tail -10

2. Multicore CPU

By using stream API, we can express our logic at a high level and the execution part is taken care of by Stream Library. As part of this, developers need to worry about synchronizing. The synchronized keyword makes to put many efforts to handle the errors caused by multiple threads. This stream API avoids high error-prone and uses multi-core CPU effectively.

If we do not use much multi-threading then we will not be using all the cores in the CPU.  That means not utilizing all core properly. So, We will experience performance issues If we don't use all the core properly. Java 8 has been developed after considering all these issues.

Java 8 stream API consumes all available core effectively and improves the performance significantly. 

3. Anonymous Inner class

Prior to Java 8, Anonymous inner classes are widely used by all the developers.

Inerface AddOn {
 boolean addAddon(String addOnType);
}

public void processingCreditCardAddOn(int cardNumber, AddOn addOn){

 boolean isValid = ValidateAccountNumber(cardNumber);
 if(isValid){
  addOn.addAddon("Extra Reward Points")
 }
}

When we call the processingCreditCardAddOn() method from service class, the implementation for the AddOn interface. Instead of creating a new class with implementation, We can pass the anonymous class to this method as below.

processor.processingCreditCardAddOn(1234567898765432, new AddOn() {
 public boolean addAddon(String addOnType){
  
  //logic to add the addOnType to the given account number.
 }
})

Now the code has become non readable and looks ugly by seeing anonymous class implementation.
The same can be simplified and making it more readable using Lambda concept.

processingCreditCardAddOn(1234567898765432, (addOnType) ->  //logic to add the addOnType to the given account number );

4. Stream Pipe Line


Java Stream API is developed mainly for Big Data application to process the large data sets effectively using all the hardware.

Example on Stream API to find the error in the log file.

First converting the log content into stream.

Stream stream = Stream.of(responseContent.split("\n"));

String firstException = stream.filter(line -> line.indexOf("ERROR") > -1 || line.indexOf("Exception) > -1).findFirst();


Here, First a pipe line will be created and every operation that perform on stream are placed in this pipe line. In other words, After that what ever we do like filter(), map() etc all the operations are placed into pipe line. But all not executed immediately unless invoke terminal methods.

Terminal methods that close the stream by producing the result. Terminal methods examples are reduce(), count(), findFirst() etc.

Once any terminal method is invoked than code is optimized by API and executes in the best order.

5. Functional Interfaces


To work with streams, we must have an idea about functional interface.
If any interface has only one abstract method then it is called Functional Interfaces. Functional Interfaces can have any number of default and private methods.

Filter(), Map()
methods will be using internally Functional Interfaces.

Examples are BiConsumer, Predicate, BinaryOperator, Function. All these are in java.util.function package.


Find list of all Functional Interfaces introduced in Java 8.

6. Stream API Intermediate Operations


Every stream code or pipeline must-have a map() or filter() methods. These methods are called as Intermediate Functions because these methods again create a temporary Stream to hold the intermediate output.

Learn about all intermediate stream operations in-depth.

filter()
map()
flatMap()
distinct()
sorted()
peek()
limit()
skip()


7. Stream API Terminal Operations


After calling the intermediate methods, to collect the final output stream api has another set of methods. Those are called Terminal Operations. These methods produce output such as Collection, List, Set, or Optional values.

I have shown an in-depth tutorial on Terminal Operations.

toArray()
collect()
count()
reduce()
forEach()
forEachOrdered()
min()
max()
anyMatch()
allMatch()
noneMatch()
findAny()
findFirst()

8. Java 8 Examples


9. Conclusion


In this tutorial, We've seen an introduction to the new java 8 Stream API.

Next, the Seen impact of Multi-core CPU usage as compared to utilizing only single core without threading in the collection API.

Furthermore discussed Anonymous Inner classes and how lambda is replaced it.

Finally, Seen how the stream pipeline works and Functional Interfaces.

No comments:

Post a Comment

Please do not add any spam links in the comments section.