Introduction to Java 8 Streams

Introduction to Java 8 Streams

In this post, we will get a quick Introduction to Java 8 Streams API, a new feature introduced in Java 8. We will try to get a high level of understanding as what is stream and how this is useful in our day-to-day work.

 

Introduction

Streams are one of the most important APIs introduced in Java 8 and completely changes the way we do processing of Collections in Java. This is in line with the theme of Java since past few versions where advances in hardware are exploited by the language.

 

1. Why Java 8 Streams

Before diving into ‘What’ of Streams, let us get into ‘Why’. Why were Streams introduced and what
problem they solve? Let us see the code below:

private static HashMap<String, Integer> myIterator(List<String> inList) {
    Iterator<String> thisIterator = inList.iterator();
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    while (thisIterator.hasNext()) {
        String str = thisIterator.next();
        if (str.length() > 5) {
            map.put(str, str.length());
        }
    }
    return map;

}

Above code is not doing anything fancy or complicated but it takes in a List of String, calculates the length of each String in List and puts the String, String Length in a HashMap if length greater than 5. It is definitely solving our problem but there are multiple problems with above code.

  1. The code is sequential and in spite of my computer being a Quad core system, I am not exploiting computer’s processing power here.
  2. Simply, too much code for a simple task.
  3. As a programmer, I need to work on the lower level aspects of the program. I have to take care of ‘how’ the iteration takes place apart from the program logic. Such programmer drove iteration known as External Iteration. It can have optimization issues in complex and data-intensive programs.

 

2. Code Simplifaction using Java Streams

Java Streams help us address the above-mentioned issues by completely abstracting out the low-level parallelism logic and Iteration logic. Putting in the most simple way, Java Streams convert Collections to a Stream, process the elements in parallel by performing multiple operations and again gather the final elements into a Collection.

Java Stream API helps us do above mention by implementing internal iteration. It lets the framework perform a sequential and parallel execution, mapping elements and criteria based filtering. Java framework is in control of the resulting iteration and lets the developer fully concentrate on the data and various operations to be performed on it.

Java Stream API implements functional interfaces as its API methods, which ties up well with Lambda expressions, which is another pillar of Java 8. Together they make the Java 8 a true ‘functional’ language. Thus, when we use Java Streams, the code mentioned above turns into a single line code.

private static Map<String, Integer> myIterator(List<String> inList) {

    return inList.stream().filter(str -> str.length() > 5).
            collect(Collectors.toMap(str -> str, str -> str.length()));
}

Here inList is a List of Strings. Stream method takes the inList and streams it into a filter. The filter passes only those Strings which meet the criteria (String.length>5). Collect method takes in the filtered Strings and sends them to Collector.toMap() function which inserts the String and their Lengths in the Map. In a single line of code, we utilize the Streaming, Filtering and Collection mechanisms of the API thus writing a more efficient code.

 

3. Steams API Benefits

let’s see other important aspects of Streams.

Streams are on-demand Data Structures. They don’t store data and instead take in a Data Structure(mainly Collections) as the source to produce a pipeline of that Collection. On this pipeline, desired functions can be called further to harness the power of in-memory computation.

Streams support Parallel Processing and Sequential Processing both, giving the developer options to use whatever mechanism as per the requirement. For large collections, Parallel Processing can work wonders in terms of achieving great performance. Streams support Lazy computation, that means we do these operations only when we need it and not when defined in the Streams. This leads to higher performance and optimization of the programs than the traditional methods.

Streams have two types of Operations: Intermediate and Terminal. All those Stream operations which return a new Stream are known as intermediate operations. These never return the final result of the operations and help in building a pipeline from one operation to another. filter and map are two such operations.

All Stream operations which return a result are Terminal operations. They are eager computations which process Stream elements before returning results and they consume the Stream. After consumption by these operations, Streams are no more available for further processing. They can be identified by their return types as they would not produce any further Streams. Examples are:forEach, toArray, min, max etc.

 

Summary

This was a very high level and a brief Introduction to Java 8 Streams API. We saw the benefits and features brought by Java Streams and their use to write more concise and easily readable code. Stay tuned to our website for further content on Streams and other in-depth content in Java.

Aditya Gupta

Aditya Gupta is a Technical Architect with 10 years of experience in the IT industry. He has worked on the design and development of Digital Transformation and Mission Critical Systems for Retail, eCommerce, FMCG, Telecom, Defense and Government Domains.

He has worked on Big Data Analytics, Data Pipelines, and full stack systems. His interests include Machine Learning, Robotics, CyberSecurity and Cloud Scale systems. He can be reached at Email Aditya Gupta

4
Leave a Reply

avatar
3 Comment threads
1 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
Umesh AwasthiRon Wheeler Recent comment authors

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
newest oldest most voted
Notify of
Ron Wheeler
Guest
Ron Wheeler

Handling Exceptions generated by functions called within Streams seems to be problematic.
Do you have any advice or examples that show best practices?

Umesh Awasthi
Admin
Umesh Awasthi

Hello Ron,

I can think of following ways but it will be dependent upon particular use case

1. We can wrap method call in another one and it will give us a chance to handle it the way we want (throwing runtime exception in place of check exception etc.)
2. We can think of aggregate our exceptions.

trackback
New Features in Java 8 | Java Development Journal

[…] Interface introduced in Java8 as new features along with Stream API, Time API, Lambda Expression, etc., Function Interface having only one abstract method which means […]

trackback
The Java 8 Stream API | Java Development Journal

[…] we are going to cover Java 8 Stream in details. If you are starting with Java 8 Stream, please read Introduction to Java 8 Streams for the basic […]