• iconJava Online Training In Andhra Pradesh and Telangana
  • icon9010519704

Opening Hours :7AM to 9PM

Java Streams



In this guide, we will discuss Stream API which is another new feature of java 8. All the classes and interfaces of this API is in the java.util.stream package. By using streams we can perform various aggregate operations on the data returned from collections, arrays, Input/Output operations. Before we see how stream API can be used in Java, let’s see an example to understand the use of streams. Java Stream Example To understand how stream works, lets take an example without using stream and then we will see the same example with streams.
Java Stream Example
To understand how stream works, lets take an example without using stream and then we will see the same example with streams.
Finding certain strings without using Stream-P1
import java.util.ArrayList;
import java.util.List;
public class Example{ 
  public static void main(String[] args) {    
  List<String> names = new ArrayList<String>();
  names.add("Ajeet");
  names.add("Negan");
  names.add("Aditya");
  names.add("Steve");
  int count = 0;  
  for (String str : names) {
     if (str.length() < 6) 
    count++; 
  }
        System.out.println("There are "+count+" strings with length less than 6");
   }  
}

Output:
There are 3 strings with length less than 6

Same example using Stream P2

import java.util.ArrayList;
import java.util.List;
public class Example{ 
  public static void main(String[] args) {    
  List<String> names = new ArrayList<String>();
  names.add("Ajeet");
  names.add("Negan");
  names.add("Aditya");
  names.add("Steve");
    
  //Using Stream and Lambda expression
  long count = names.stream().filter(str->str.length()<6).count();
  System.out.println("There are "+count+" strings with length less than 6");

   }  
}
Output:
There are 3 strings with length less than 6
What is the difference between these codes?
The output of both the examples are same, however there is a major difference between these examples if you consider the performance of the code.

In the first example, we are iterating the whole list to find the strings with length less than 6. There is no parallelism in this code.

In the second example, the stream() method returns a stream of all the names,
the filter() method returns another stream of names with length less than 6,
the count() method reduces this stream to the result.
All these operations are happening parallelly which means we are able to parallelize the code with the help of streams. Parallel execution of operations using stream is faster than sequential execution without using streams.
How to work with Stream in Java
As we have seen in the above example, the working of stream can be explained in three stages:
1. Create a stream
2. Perform intermediate operations on the initial stream to transform it into another stream and so on on further intermediate operations. In the above example, the filter() operation is intermediate operation, there can be more than one intermediate operations.
3. Perform terminal operation on the final stream to get the result. In the above example, the count() operation is terminal operation.

Java Stream Features
1. Stream does not store the elements. it simply performs the aggregate operations(such as filter() and count() that we have seen in the above example) to get the desired stream of data.

2. The aggregate operations that we perform on the collection, array or any other data source do not change the data of the source, they simply return a new stream. For example the code we have seen above is filtering the strings with length less than 6 using the stream operations but it didn’t change the elements of the list.

3. All the stream operations are lazy in nature which means they are not executed until they are needed. For example, if we want to display only the first 2 elements of a list using stream, the stream operation would stop at the end of second iteration after displaying the second element of list.

Java Streams Program- P3

Display 1-10 Numbers Using Streams -P3
import java.util.stream.*;  
public class Main {  
    public static void main(String[] args){  
        Stream.iterate(1, count->count+1)  
        
        .limit(10)  
        .forEach(System.out::println);  
        //.forEach(x->System.out.println(x))
    }  
}
                               

Output:
Java Streams Program- P4

Display Even Numbers Using Streams -P4
import java.util.stream.*;
class Demo
{
public static void main(String args[])
{
Stream.iterate(1,x->x+1)
.filter(y->y%2==0)

.limit(10)
.forEach(System.out::println);
}
}
                                

Output:
Java Streams Program- P5

Display Even and Perform Operation Numbers Using Streams -P5
import java.util.stream.*;
class Demo
{
public static void main(String args[])
{
Stream.iterate(1,x->x+1)
.filter(y->y%2==0)
.map(p->p*2)
.limit(10)
.forEach(System.out::println);
}
}                             

Output:
Stream Filter with examples -P6
In the previous tutorial, we learned about Java Stream. I would recommend you to read that guide before going through this tutorial. In this guide, we will discuss the Java stream filter. The filter() is an intermediate operation that reads the data from a stream and returns a new stream after transforming the data based on the given condition. Lets take a simple example first and then we will see the examples of stream filter with other methods of the stream.

A Simple Example of Java Stream Filter() -P6
In this example we are creating a stream from the list of names using stream() method and then we are creating another stream of long names using stream filter(). As I mentioned above, the stream filter transforms the data of one stream into another stream.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class Example {
   public static void main(String[] args) {

  List<String> names = Arrays.asList("Melisandre","Sansa","Jon","Daenerys","Joffery");
    
  //Creating the stream of all names
  Stream<String> allNames = names.stream();
    
  //Creating another stream by filtering long names using filter()
  Stream<String> longNames = allNames.filter(str -> str.length() > 6);

    

  //displaying the long names
longNames.forEach(str->System.out.print(str+" "));
//longNames.forEach(System.out::print);



  }
}
                                

Output:
Melisandre Daenerys Joffery
Stream filter() and collect() -P7
We can create a stream and apply a filter in a one line as shown in the example below. The collect() method here collects the final stream and converts it into a list

A Simple Example of Java Stream Filter() -P7

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Example {

    public static void main(String[] args) {

        List<String> names = Arrays.asList("Melisandre","Sansa","Jon","Daenerys","Joffery");

        List<String> longnames = names.stream()    // converting the list to stream
                .filter(str -> str.length() > 6)   // filter the stream to create a new stream
                .collect(Collectors.toList());  // collect the final stream and convert it to a List

        longnames.forEach(System.out::println);           

    }

}
                                

Output:
Melisandre Daenerys Joffery
Stream filter() with multiple conditions -P8
In the above examples we have seen that there is only one condition in the filter() method. We can have more than one conditions in the filter() method joined using the logical operators in java. In the following example, we have two conditions in the filter method joined using and (&&) logical operator.

A Simple Example of Java Stream Filter() -P8

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Example {

    public static void main(String[] args) {

        List<String> names = Arrays.asList("Melisandre","Sansa","Jon","Daenerys","Joffery");

        List<String> longnames = names.stream()  
                .filter(str -> str.length() > 6 && str.length() < 8) //Multiple conditions
                .collect(Collectors.toList());  

        longnames.forEach(System.out::println);           

    }

}
                                

Output:
1.Filter a Map by keys and values -P9
Examples: 1

Filter Map by Key -P9

import java.util.*;
import java.util.stream.*;
 
class strex9
{
public static void main(String args[])
{
Map<Integer,String> M=new HashMap<Integer,String>();
M.put(91,"hyd");
M.put(2,"del");
M.put(3,"hyd2");
M.put(24,"hyd3");
M.put(5,"hyd4");
 
 
 
Map<Integer,String> output=M.entrySet().stream()
.filter(x->x.getKey().intValue()>3)
.collect(Collectors.toMap(p->p.getKey(),p->p.getValue()));
System.out.println(output);
}
}
                            

Output:
1.Filter a Map by keys and values -P10
Examples: 2

Filter Map by Values -P10

import java.util.*;
import java.util.stream.*;
 
class strex10
{
public static void main(String args[])
{
Map<Integer,String>  M=new HashMap<Integer,String>();
M.put(91,"hyd");
M.put(2,"del");
M.put(3,"del");
M.put(24,"hyd3");
M.put(5,"hyd4");
 
 
 
Map<<Integer,String>  output=M.entrySet().stream()
.filter(x-> "del".equals(x.getValue()))
.collect(Collectors.toMap(p->p.getKey(),p->p.getValue()));
System.out.println(output);
}
}

                                

Output:
1.Filter a Map by keys and values -P11
Examples: 3

Filter Map by both Keys and Values-P11

import java.util.*;
import java.util.stream.*;
 
class strex11
{
public static void main(String args[])
{
Map<Integer,String>M=new HashMap<Integer,String>();
M.put(91,"hyd");
M.put(2,"del");
M.put(3,"del");
M.put(24,"hyd3");
M.put(5,"dhyd4");
 
 
 
Map<Integer,String> output=M.entrySet().stream()
.filter(y->y.getKey().intValue()>2)
.filter(x->x.getValue().startsWith("d"))
.collect(Collectors.toMap(p->p.getKey(),p->p.getValue()));
System.out.println(output);
}
}
                                

Output:
4.A stream with null values -P12
Examples: 4

A stream with null values-P12

import java.util.*;
import java.util.stream.*;
 
class strex12
{
public static void main(String args[])
{
 
List<String> ar = Arrays.asList("Java", "Stream", null, "Filter", null);
 
List<String> op=ar.stream().collect(Collectors.toList());
op.forEach(x->System.out.println(x));
}
}

                                

Output:
5.Filter null values from a stream -P13
Examples: 5

Filter null values from a stream-P13
import java.util.*;
import java.util.stream.*;
 
class strex13
{
public static void main(String args[])
{
 
List<String> ar = Arrays.asList("Java", "Stream", null, "Filter", null);
 
List<String> op=ar.stream()
.filter(s->s!=null)
 
.collect(Collectors.toList());
op.forEach(x->System.out.println(x));
}
}

                                

Output:
6.Filter null values after map in mtermediate operation -P14
Examples: 6

Filter null values after map in mtermediate operation-P14
import java.util.*;
import java.util.stream.*;
 
class strex14
{
public static void main(String args[])
{
 
List<Integer> ar = Arrays.asList( 12,13, null, 21, null);
 
List<Integer> op=ar.stream()
.filter(s->s!=null)
.map(d->d*d)
 
.collect(Collectors.toList());
op.forEach(x->System.out.println(x));
}
}

                                

Output:
forEach method with example -P15
In Java 8, we have a newly introduced forEach method to iterate over collections and Streams in Java. In this guide, we will learn how to use forEach() and forEachOrdered() methods to loop a particular collection and stream.

forEach to iterate a Map p-15
import java.util.Map;
import java.util.HashMap;
public class Example {
   public static void main(String[] args) {
      Map<Integer, String> hmap = new HashMap<Integer, String>();
      hmap.put(1, "Monkey");
      hmap.put(2, "Dog"); 
      hmap.put(3, "Cat");  
      hmap.put(4, "Lion");   
      hmap.put(5, "Tiger");   
      hmap.put(6, "Bear");
      /* forEach to iterate and display each key and value pair
       * of HashMap.    
       */  

      hmap.forEach((key,value)->System.out.println(key+" - "+value));

      /* forEach to iterate a Map and display the value of a particular  
       * key     
       */ 

      hmap.forEach((key,value)->{ 
         if(key == 4){ 
            System.out.println("Value associated with key 4 is: "+value); 
         }  
      });

      /* forEach to iterate a Map and display the key associated with a
       * particular value     
       */

      hmap.forEach((key,value)->{
         if("Cat".equals(value)){ 
            System.out.println("Key associated with Value Cat is: "+key);
         }
      }); 
   }
}

                                

Output:
forEach to iterate a List p-16
In this example, we are iterating an ArrayList using forEach() method. Inside forEach we are using a lambda expression to print each element of the list.

forEach to iterate a List p-16
import java.util.List;
import java.util.ArrayList;
public class Example {
   public static void main(String[] args) {
      List<String> fruits = new ArrayList<String>();
      fruits.add("Apple");
      fruits.add("Orange");
      fruits.add("Banana");
      fruits.add("Pear"); 
      fruits.add("Mango");
      //lambda expression in forEach Method 
      fruits.forEach(str->System.out.println(str));
   }
}
                               

Output:
Apple
Orange
Banana
Pear
Mangohh

We can also use method reference in the forEach() method like this:
fruits.forEach(System.out::println);
forEach method to iterate a Stream p-17
In this example we are iterating a Stream in Java using forEach() method.

forEach method to iterate a Stream p-17
import java.util.List;
import java.util.ArrayList;
public class Example {
   public static void main(String[] args) {
      List<String> names = new ArrayList<String>();
      names.add("Maggie");
      names.add("Michonne");
      names.add("Rick");
      names.add("Merle");
      names.add("Governor");
      names.stream() //creating stream 
     .filter(f->f.startsWith("M")) //filtering names that starts with M 
     .forEach(System.out::println); //displaying the stream using forEach
   }
}
                              

Output:
Maggie
Michonne
Merle

Stream forEachOrdered() Method Example p-18
For sequential streams the order of elements is same as the order in the source, so the output would be same whether you use forEach or forEachOrdered. However when working with parallel streams, you would always want to use the forEachOrdered() method when the order matters to you, as this method guarantees that the order of elements would be same as the source. Lets take an example to understand the difference between forEach() and forEachOrdered().

Stream forEachOrdered() Method Example p-18
import java.util.List;
import java.util.ArrayList;
public class Example {
   public static void main(String[] args) {
      List<String> names = new ArrayList<String>();
      names.add("Maggie"); 
      names.add("Michonne");
      names.add("Rick");
      names.add("Merle");
      names.add("Governor"); 
      //forEach - the output would be in any order
      System.out.println("Print using forEach");
      names.stream() 
     .filter(f->f.startsWith("M"))
     .parallel() 
     .forEach(n->System.out.println(n)); 
 
     /* forEachOrdered - the output would always be in this order: 
      * Maggie, Michonne, Merle 
      */ 
     System.out.println("Print using forEachOrdered"); 
     names.stream()  
     .filter(f->f.startsWith("M"))  
     .parallel() 
     .forEachOrdered(n->System.out.println(n));
   }
}
                              

Output:
Print using forEach
Merle
Maggie
Michonne

Print using forEachOrdered
Maggie
Michonne
Merle

Stream Collectors Class with examples p-19
Collectors is a final class that extends the Object class. In this tutorial we will see the examples of Java Stream collectors class using lambda expressions, Java Streams and other new features of Java 8.
java.lang.Object
   |
   |___java.util.stream.Collectors
   

Java – Stream Collectors groupingBy and counting Example p-19
In this example, we are grouping the elements of a list using groupingBy() method of Collectors class and printing the occurrences of each element in the list.
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
 
public class Example {
 
   public static void main(String[] args) {
 
      List<String> names =
          Arrays.asList("Jon", "Ajeet", "Steve",
             "Ajeet", "Jon", "Ajeet");
 
      Map<String, Long> map =
      names.stream().collect(
          Collectors.groupingBy(
             Function.identity(), Collectors.counting()
          )
      );
 
      System.out.println(map);
 
   }
}

                              

Output:
{Steve=1, Jon=2, Ajeet=3}
Stream Collectors example of fetching data as List p-20

Stream Collectors example of fetching data as List Example p-20
import java.util.stream.Collectors; 
import java.util.List;  
import java.util.ArrayList;  
class Student{  
   int id;	 
   String name;	
   int age;	     
   public Student(int id, String name, int age) {  
        this.id = id;	
        this.name = name;	     
        this.age = age;	 
   } 
}  
public class Example {  
   public static void main(String[] args) {	
      List<Student> studentlist = new ArrayList<Student>();   
      //Adding Students      
      studentlist.add(new Student(11,"Jon",22));	  
      studentlist.add(new Student(22,"Steve",18));	    
      studentlist.add(new Student(33,"Lucy",22));	    
      studentlist.add(new Student(44,"Sansa",23));	     
      studentlist.add(new Student(55,"Maggie",18));	 
      
      //Fetching student names as List       
      List<String> names = studentlist.stream() 
                                   .map(n->n.name) 
                                   .collect(Collectors.toList());
      System.out.println(names);         
   }  
}


                              

Output:
[Jon, Steve, Lucy, Sansa, Maggie]
Java Collectors Example – Collecting Data as Set p-21
In this example we are converting the list of students to the stream and then we are applying the Java Stream filter to get the selected records from the stream, after that we are converting that stream to set using Collectors.toSet() method.

Java Collectors Example – Collecting Data as Set Example p-21
import java.util.stream.Collectors;  
import java.util.List;  
import java.util.Set; 
import java.util.ArrayList;  
class Student{	
   int id;	 
   String name;  
   int age;	  	 
   public Student(int id, String name, int age) {   
       this.id = id;	     
       this.name = name;	   
       this.age = age;	  
   } 
}  
public class Example {	 
   public static void main(String[] args) {	   
      List<Student> studentlist = new ArrayList<Student>();	   
      //Adding Students        
      studentlist.add(new Student(11,"Jon",22));	     
      studentlist.add(new Student(22,"Steve",18));	     
      studentlist.add(new Student(33,"Lucy",22));	     
      studentlist.add(new Student(44,"Sansa",23));	     
      studentlist.add(new Student(55,"Maggie",18));	    	      
      //Fetching student data as a Set       
      Set<Student> students = studentlist.stream()
                           .filter(n-> n.id>22)
                           .collect(Collectors.toSet());
      //Iterating Set       
      for(Student stu : students) { 
         System.out.println(stu.id+" "+stu.name+" "+stu.age); 
      }      	 
   } 
}


                              

Output:
44 Sansa 23
33 Lucy 22
55 Maggie 18

Java Collectors Example – Getting the average age of students using averagingInt() method p-22

Java Collectors Example – Getting the average age of students using averagingInt() method Example p-22
import java.util.stream.Collectors;  
import java.util.List;  
import java.util.ArrayList; 
class Student{  
   int id;   
   String name;   
   int age;
   public Student(int id, String name, int age) {  
      this.id = id;   
      this.name = name; 
      this.age = age;  
   } 
}  
public class Example {  
   public static void main(String[] args) {  
      List<Student> studentlist = new ArrayList>Student>();  
      //Adding Students  
      studentlist.add(new Student(11,"Jon",22));   
      studentlist.add(new Student(22,"Steve",18));   
      studentlist.add(new Student(33,"Lucy",22));   
      studentlist.add(new Student(44,"Sansa",23));   
      studentlist.add(new Student(55,"Maggie",18));
      //Getting the average Age 
      Double avgAge = studentlist.stream()   
          .collect(Collectors.averagingInt(s->s.age));  
      System.out.println("Average Age of Students is: "+avgAge);
   }  
}


                              

Output:
Average Age of Students is: 20.6
StringJoiner with example p-23
In java 8, a new class StringJoiner is introduced in the java.util package. Using this class we can join more than one strings with the specified delimiter, we can also provide prefix and suffix to the final string while joining multiple strings. In this tutorial we will see several examples of StringJoiner class and at the end of this guide, we will see the methods of StringJoiner class.

Java StringJoiner Example 1: Joining strings by specifying delimiter Example p-23
In this example, we are concatenating multiple strings using StringJoiner. While creating the instance of StringJoiner, we have specified the delimiter as hyphen(-).
import java.util.StringJoiner;  
public class Example {  
    public static void main(String[] args) {  
    	// Passing Hyphen(-) as delimiter
        StringJoiner mystring = new StringJoiner("-");    
          
        // Joining multiple strings by using add() method  
        mystring.add("Logan");  
        mystring.add("Magneto");  
        mystring.add("Rogue");  
        mystring.add("Storm");  
                  
        // Displaying the output String
        System.out.println(mystring);  
    }  
}


                              

Output:
Logan-Magneto-Rogue-Storm
Java StringJoiner Example 2: Adding prefix and suffix to the output String p-24

Java StringJoiner Example 2: Adding prefix and suffix to the output String Example p-24
import java.util.StringJoiner;  
public class Example {  
    public static void main(String[] args) {  
    	/* Passing comma(,) as delimiter and opening bracket
    	 * "(" as prefix and closing bracket ")" as suffix
    	 */
        StringJoiner mystring = new StringJoiner(",", "(", ")");    
          
        // Joining multiple strings by using add() method  
        mystring.add("Negan");  
        mystring.add("Rick");  
        mystring.add("Maggie");  
        mystring.add("Daryl");  
                  
        // Displaying the output String
        System.out.println(mystring);  
    }  
}


                              

Output:
(Negan,Rick,Maggie,Daryl)
StringJoiner Example 3: Merging two StringJoiner objects p-25

Merging two StringJoiner objects Example p-25
import java.util.StringJoiner;  
public class Example {  
   public static void main(String[] args) {  
	/* Passing comma(,) as delimiter and opening bracket
	 * "(" as prefix and closing bracket ")" as suffix
	 */
	StringJoiner mystring = new StringJoiner(",", "(", ")");    
 
	mystring.add("Negan");  
	mystring.add("Rick");  
	mystring.add("Maggie");  
	mystring.add("Daryl");  
 
	System.out.println("First String: "+mystring);
 
	/* Passing hyphen(-) as delimiter and string "pre"
	 * as prefix and string "suff" as suffix
	 */
	StringJoiner myanotherstring = new StringJoiner("-", "pre", "suff");    
 
	myanotherstring.add("Sansa");  
	myanotherstring.add("Imp");  
	myanotherstring.add("Jon");  
	myanotherstring.add("Ned"); 
 
	System.out.println("Second String: "+myanotherstring);
 
	/* Merging both the strings  
	 * The important point to note here is that the output string will be 
	 * having the delimiter prefix and suffix of the first string (the string
	 * which is calling the merge method of StringJoiner)
	 */
	StringJoiner mergedString = mystring.merge(myanotherstring);   
	System.out.println(mergedString);  
   }  
}



                              

Output:
First String: (Negan,Rick,Maggie,Daryl)
Second String: preSansa-Imp-Jon-Nedsuff
(Negan,Rick,Maggie,Daryl,Sansa-Imp-Jon-Ned)
In the above examples, we have seen the add() and merge() methods of StringJoiner class. Lets see the other methods of this class.
StringJoiner Example: setEmptyValue(), length() and toString() methods p-26

StringJoiner Example: setEmptyValue(), length() and toString() methods Example p-26
import java.util.StringJoiner;  
public class Example {  
    public static void main(String[] args) {  
    	//Comma(,) as delimiter
        StringJoiner mystring = new StringJoiner(",");  
        
        /* Using setEmptyValue() method, we can set the default value
         * of a StringJoiner instance, so if the StringJoiner is empty
         * and we print the value of it, this default value will be
         * displayed
         */
        mystring.setEmptyValue("This is a default String");  
        
        /* We have not added any string to StringJoiner yet so
         * this should display the default value of StringJoiner
         */
         
        System.out.println("Default String: "+mystring);  
          
          
        // Adding strings to StringJoiner  
        mystring.add("Apple");  
        mystring.add("Banana"); 
        mystring.add("Orange");
        mystring.add("Kiwi");
        mystring.add("Grapes");
        System.out.println(mystring);  
          
        /* The length() method of StringJoiner class returns the 
         * length of the string (the number of characters in the 
         * StringJoiner instance)
         */
         
        int length = mystring.length();  
        System.out.println("Length of the StringJoiner: "+length);  
          
        /* The toString() method is used for converting a StringJoiner
         *  instance to a String. 
         */
         
        String s = mystring.toString();  
        System.out.println(s);   
    }  
}



                              

Output:
Default String: This is a default String
Apple,Banana,Orange,Kiwi,Grapes
Length of the StringJoiner: 31
Apple,Banana,Orange,Kiwi,Grapes

Optional Class p-27
In Java 8, we have a newly introduced Optional class in java.util package. This class is introduced to avoid NullPointerException that we frequently encounters if we do not perform null checks in our code. Using this class we can easily check whether a variable has null value or not and by doing this we can avoid the NullPointerException. In this guide, we will see how to work with Optional class and the usage of various methods of this class. Before we see the example of Optional class, lets see what happens when we don’t use Optional class and do not perform null check.

Without using Optional class Example p-27
In this example, we didn’t assign the value to the String str and we are trying to get the substring out of it. Since there is no value present in the str, the program is throwing NullPointerException.
public class Example {  
    public static void main(String[] args) {  
    	String[] str = new String[10];
 
        //Getting the substring
        String str2 = str[9].substring(2, 5);
        //Displaying substring
        System.out.print(str2);  
    }  
}



                              

Output:
Exception in thread "main" java.lang.NullPointerException at Example.main(Example.java:5)
Solution: Using Optional Class p-28
Optional.ofNullable() method of the Optional class, returns a Non-empty Optional if the given object has a value, otherwise it returns an empty Optional. We can check whether the returned Optional value is empty or non-empty using the isPresent() method.

Solution: Using Optional Class Example p-28
//Importing Optional class
import java.util.Optional; 
public class Example { 
   public static void main(String[] args) {	
      String[] str = new String[10];	
 
 
      Optional isNull = Optional.ofNullable(str[9]);	    
      if(isNull.isPresent()){     
         //Getting the substring           
         String str2 = str[9].substring(2, 5);          
         //Displaying substring           
         System.out.print("Substring is: "+ str2);       
      }     
      else{      
         System.out.println("Cannot get the substring from an empty string");     
      } 
               
      str[9] = "AgraIsCool";       
      Optional isNull2 = Optional.ofNullable(str[9]);       
      if(isNull2.isPresent()){        
         //Getting the substring            
         String str2 = str[9].substring(2, 5);            
         //Displaying substring           
         System.out.print("Substring is: "+ str2);          
      }         
      else{         
         System.out.println("Cannot get the substring from an empty string");         
      }    
   }  
}



                              

Output:
Cannot get the substring from an empty string Substring is: raI
Optional.map and Optional.flatMap p-29
In this example, we will see how Optional works with map and flatMap.

map Example p-29
import java.util.List; 
import java.util.*;
public class Main {   
   public static void main(String[] args) {
      
      List<Integer> n = Arrays.asList(1,2,3,4,5,6);
      n.stream()
      .map(i->i*2)
      .forEach(System.out::println);
   }
}



                              

Output:

Optional.map and Optional.flatMap p-30
In this example, we will see how Optional works with map and flatMap.

flatMap Example p-30

import java.util.List; 
import java.util.*;
import java.util.stream.Stream;
public class Main {   
   public static void main(String[] args) {
      
      List<Integer> n = Arrays.asList(1,2,3,4);
      n.stream()
      .flatMap(i->Stream.of(i*2,i*3,i*4))
      .forEach(System.out::println);
   }
}





                              

Output: