Java8: Oogways Advice on Optional

While PO reading Java 8 Optional he has few question in mind and can not understand why Optional added in Java, How it saves us from the almighty villain null pointer Exception. So he goes to master Shifu, But the Irony is Shifu does not sure about How it will save Java users from the null pointer, but it is oogways foretold so they go to Oogways for advice on Optional.
I was there when the conversation happened, I will try to depict the conversation.
PO : Master oogways, I am really confused why Optional added in Java, I can't see any benefits , and I am bit skeptical how it saves from Nullpointer exception as it is nothing but a Container/Wrapper Object which held a reference to another Object, So the reference can be null and itself Optional wrapper class can be null, so I am confused what is the use case.
Oogway: From the birth of java the greatest sin is, The invention of null, Java tries to represent something absent as a null, but absent does not mean null it means not present. Java is a strong type language but null is such a value which can be assigned to any type, so it acts as a loose type variable, act as default value of reference, It is not blessing but a curse,
Every time we don't know what would be the returned Object, developers returns a null, and caller, unfortunately, bears the load of the null check for return value unless null pointer exception blows up the flow.
Let see a small example,

package com.example.optional;

import java.util.ArrayList;
import java.util.List;

public class OptionalTest {
private static List<String> nameList = new ArrayList<String>();
static{
nameList.add("Shamik");
nameList.add("Samir");
nameList.add("Swastika");
}

public String findName(String nameToFind){
return nameList.contains(nameToFind)?nameList.get(nameList.indexOf(nameToFind)):null;
}

public static void main(String[] args) {
OptionalTest test = new OptionalTest();
String searchedName = test.findName("Mayukh");
System.out.println(" Hi , " + searchedName.toUpperCase());
}


}
Here, The API developer exposes a method called findName, and silently return a null if the name is not found.  The caller of the API trust the API developer and called the method with an arbitrary name and try to print it in Uppercase. But it blows the caller's code with null pointer exception.
Whose fault is it Callers or API developer?

API Developers Perspective: When caller gives a name and that name is not found in nameList what should I do? return a blank string or return a String "NA" but if the caller says that they don't want "NA" or blank String, or One caller OK with the blank or "NA" String  and Other wants to handle the scenario by itself, so  as a developer when I am not sure what to return I always returns null. Yes, I am a good developer I can handle all the boundary cases.
Callers Perspective: findName is an API method I only command it to give me a search result "Tell Don't Ask", It is API method responsibility to handle boundary cases or cases if the searchable name is not found, It should give me a dummy implementation if the searchable name not found, like "NA". So I do not bother to check the return value, It is not my responsibility, so he skips the null check and programs blown up.

Really who's fault it is API developer or Caller?
Caller and Developer are right in their perspective, the confusion grows because API developer can't signal the caller, The return value may be present or absent. Null means no reference !!! (But How caller will  Understand current retuned reference not point to any Object instance?), so always it is caller responsibility to do a null check even if the value is present. null is not so expressive, to indicate caller a value is present or absent as it can be easily assigned to return value silently. So Optional step in here it tries to say value may be present or may be absent so caller it is your duty to check value is present or absent whereas null returns silently without informing the nature of the value.
Optional is acting as a Container, It holds the reference and provides some method to test the reference inside is present or absent.
Let see How we can return Optional with above example.

package com.example.optional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class OptionalTest {
private static List<String> nameList = new ArrayList<String>();
static{
nameList.add("Shamik");
nameList.add("Samir");
nameList.add("Swastika");
}

public Optional<String> findName(String nameToFind){
return nameList.contains(nameToFind)?Optional.of(nameList.get(nameList.indexOf(nameToFind))):Optional.empty();
}

public static void main(String[] args) {
OptionalTest test = new OptionalTest();
Optional<String> searchedName = test.findName("Mayukh");
if(searchedName.isPresent()){
System.out.println("HI,"+ searchedName.get());
}else{
System.out.println("Name not found");
}
}

}




Here, I use Optional.of() method which creates a new Optional object with the value passed in the 'of' method as a parameter, and if the value is not found in nameList I return and Empty optional which does not contain anything, don't say it contains a null, Empty represents the Value is absent, In this way we say to the caller, my method may gives you a result which does not contain anything so prepare for it.
PO : Master Oogways I understood your point but still I have  confusions, here caller has to check if(Optional.ispresent()) to get a value which is present but if caller forget to do this check, It gives you a NoSuchElement Exception, So what is the value to use optional -- seems it changed the null pointer exception to NoSuchElement Exception, nothing else, I don't see a point here to use Optional, It can't shield us from Null Pointer Exception.
Oogway: Ha Ha, That's why I choose you as a Dragon Warrior, You are so intelligent and to the point, You learned new things very quickly. Let me share you some thoughts,
Null is Omnipresent no one can never ever remove or defeat it completely, What we can do is protect ourselves from null, educate our Java villagers from the rage of nulls.
Optional is like a warning bell in the city, rather than nulls come silently, By Optional API developers always warned  Java Villagers/ or callers, Null can be entering your village at any point of time.
So my point is, till now only efficient villagers or callers understand when to use, not null check to escape from Null pointers rage but still in a complex call or lots of chained calls they fall in the null pointers trap. Optional tries to fix that it gives remind about absent values. Absent values can come so  protect your call from that or rather always use Optional.ispresent() check with Optional.get.
Optional does not remove the null pointer exception it warns caller to handle the absent scenarios.
It is not a Technical improvement rather it is a Conceptual improvement added into Java8 which educate java programmers to handle a scenario where value can be present or absent.

PO: I realize this Master Now tell me the Best practices of Optional.
Oogway: I am too late for today, Please come Tomorrow I will discuss best practices.

Conclusion: Oogway taught us a valuable lesson Optional is not a replacement for the null check rather it tries to say caller about the nature of the returns value and implicitly reminds caller to handle the absent cases. If Caller forgets to do that it will end up with the NoSuchElementException, which is a clear evidence you are trying to do an operation where the element/value is not present. It is a big conceptual improvement, it encourages caller to handle absent cases, unlike null return value where the caller has a confusion API developer already tackle the null value or I have to do this?






Java8:Effective use of Consumer Functional Interface

Java8 provides a functional interface called Consumer, Whose signature looks like following

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
       Objects.requireNonNull(after);
       return (T t) -> { accept(t); after.accept(t); };
    }
}

So, consumer has one default method andThen and one abstract method accept. I will discuss  the andThen later, let's concentrate on accept method.

Seeing the signature of accept, one thing is clear it takes an argument and produce nothing so it returns type is void. So the consumer is logically opposite of Supplier-- which takes nothing but produce something. I can say Produces can start a flow and Consumer ends that flow, Consumer acts as a terminal operation which can complete a method chain.

By use of method reference feature in java8, we can reference any method whose signature matches the accept method of Consumer so we can refer that method as a consumer functional interface.

Let see a simple example where I want to create and display the mail (Don’t do this in production it breaks SRP, create and display should be two separate methods  It is just for example purpose).

Very basic code will look like following

package com.example.consumer;

import java.io.StringWriter;
import java.util.function.Consumer;

public class EmailManager {
   
   public void createAndDisplayEmail(String emailBody){
      StringWriter writer = new StringWriter();
      writer.append("Hi,");
      writer.append("\n");
      writer.append(emailBody);
      writer.append("\n");
      writer.append("Thanks, Shamik");
      System.out.println(writer.toString());
     
   }
   public static void main(String[] args) {
      EmailManager manager = new EmailManager();
      manager.createAndDisplayEmail("This is a mail from Javaonfly");
   }

}



Output :
Hi
This is a mail from Javaonfly
Thanks, Shamik


Nothing fancy, The createAndDisplayEmail method takes the body content then add salutation and footer to the body after that it prints the email.

As the method signature of the createAndDisplayEmail match with Consumer’s accept method signature, we can use java8 method reference and hold the reference of the createAndDisplayEmail in Consumer functional interface so we can invoke the method later when required, to achieve that we just we need to add following code snippet in the main method.


Consumer<String> consumer = manager::createAndDisplayEmail;
consumer.accept("This is a mail from Javaonfly");

After seeing the above code an inquisitive mind immediately ask two questions
1. What is the benefit of holding the reference in Consumer functional interface,
2. How that is differ from the call manager.createAndDisplayEmail("This is a mail from Javaonfly") apart from syntax.


There are several benefits by doing that, first, let me answer  the second question
How that differs from the call manager.createAndDisplayEmail("This is a mail from Javaonfly") apart from syntax?

prior to Java8, we don’t have privilege to treat method as variable so we can’t pass a method into another method as an argument like we usually do in case of variable, to achieve the same we have to pass an Object which holds that method, so to reuse the method either we have to make it static or has to pass the Object . Which is OK but it has a problem unnecessary we have to carry the context(i.e Object) while we need only the method definition. In Java 8 now we can easily hold the method reference using appropriate interface without context, and reuse the method later.

Now come to the first question,
What is the benefit of holding the reference in Consumer functional interface?

Consumer as a Strategy Pattern:

As we can hold the reference of a method in Consumer Functional interface and Consumer is an interface so we can have multiple implementations--- the question is, what are those implementation then, as Consumer holds method reference we can say it holds any methods whose method signature is matched with Consumer, and they can act as Strategy-- based on the context we can pass different method reference in to higher-order method.  so lower level methods act as an implementation of the strategy.

Hard to digest? let understand it through our Mail example

Suppose, Now we have to add new functionality into our EmaiManager class, Requirements is like that, as Javaonfly company has several departments When we send the mail that should have department specific formats and in the footer section we have to change the signature based on department.

So it is obvious the salutation, footer, the format will be changed dynamically based on the department, How we can implement the same.

Prior to Java 8, we will create an interface which has footer, salutation and format method and based on department we will implement several classes based on the department, and in EmaiManager class in createandDisplay method, we will pass the interface and email body as arguments and based on department we will pass actual implementation.

So, we need to create multiple classes, But same can be achieved very short and crisply way using Consumer interface. The Consumer is a predefined interface and can hold methods reference we will create various overloaded/separate methods based on department and then create a Higher-order function which takes Consumer interface and email body, then apply the consumer upon email body.

Let see the code

package com.example.consumer;

import java.io.StringWriter;
import java.util.function.Consumer;

public class EmailManager {
   
   
   
   public void createAnddisplayEmail(String emailBody){
      StringWriter writer = new StringWriter();
      writer.append("Hi,");
      writer.append("\n");
      writer.append(emailBody);
      writer.append("\n");
      writer.append("Thanks, Shamik");
      System.out.println(writer.toString());
     
   }
   
   public void createAnddisplayAdminEmail(String emailBody){
      StringWriter writer = new StringWriter();
      writer.append("Hi,");
      writer.append("\n");
      writer.append(emailBody);
      writer.append("\n");
      writer.append("Thanks, Admin");
      System.out.println(writer.toString());
     
   }
   
   public void createMailandDisplay(Consumer<String> consumer,String mailBody){
      consumer.accept(mailBody);
   }
   public static void main(String[] args) {
      EmailManager manager = new EmailManager();
      String body ="This is a mail from Javaonfly";
      Consumer<String> directorEmailConsumer = manager::createAnddisplayEmail;
      Consumer<String> adminEmailConsumer = manager::createAnddisplayAdminEmail;
      manager.createMailandDisplay(directorEmailConsumer, body);
      manager.createMailandDisplay(adminEmailConsumer, body);
     
   }

}

If you look at the code minutely you will find there is a higher order function called createMailandDisplay which takes mail body and consumer which act as Higher order class in the Strategy pattern and the methods createAndDisplayEmail and createAnddisplayAdminEmail are the actual implementation of the strategy which were pass from main method.

Consumer as a Filter Chain Pattern :
As Consumer takes one input and produce nothing, so it behaves like a terminal operation, but sometimes we need to apply series of actions on the input.  Generally in OO design we do it through FilterChain where we will create an interface with a method doFilter() then implements multiple classes based on the action which we apply on the input, also create a FilteManger class which iterate over the filters and apply the filter on input, or a filter apply itself then delegate the call to next filter. The Same concept can be achieved through Consumer interface where each filter implementation represents a method and a Higher-order function treat as Filter manager which will iterate over methods and apply it to the input.

Let try to solve a problem using Filter pattern,

Suppose before creating and sending any mail we want to apply spell checking, grammar checking and format checking on the email body, so that email body is error-free and well formatted. How we can achieve the same using consumer.

Obvious there is a series of actions spell check, grammar check will be applied to email body so we can use Filter pattern there.

Let see the code

package com.example.consumer;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;


public class EmailManager {
   
   public void spellChecker(String emailBody){
      System.out.println("Spell Checking on :: " + emailBody);
     
   }
   public void grammarChecker(String emailBody){
      System.out.println("Grammar Checking on :: " + emailBody);
     
   }
   public void formatChecker(String emailBody){
      System.out.println("Format Checking on :: " + emailBody);
     
   }
   
   public void applyFilter(List<Consumer<String>> filterList,String emailBody){
      filterList.forEach(filter->filter.accept(emailBody));
   }
   
   public static void main(String[] args) {
      EmailManager manager = new EmailManager();
      String body ="This is a mail from Javaonfly";
      List<Consumer<String>> filterList=new ArrayList<Consumer<String>>();
      filterList.add(manager::spellChecker);
      filterList.add(manager::grammarChecker);
      filterList.add(manager::formatChecker);
      manager.applyFilter(filterList, body);
     
   }

}



Ouput ::
Spell Cheking on :: This is a mail from Javaonfly
Grammar Cheking on :: This is a mail from Javaonfly
Format Cheking on :: This is a mail from Javaonfly


Here, I have to create a List and add the specific consumer which act as a filter, alternatively, I can use andThen functionality of the Consumer, Which takes another consumer as an input then returns a consumer which apply the consumer creates it then apply the consumer which passed as an argument. We can use this functionality which is same as filter chain.

Lets look more sophisticated version,



package com.example.consumer;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class EmailManager {
   
   public void spellChecker(String emailBody){
      System.out.println("Spell Cheking on :: " + emailBody);
     
   }
   public void grammarChecker(String emailBody){
      System.out.println("Grammar Cheking on :: " + emailBody);
     
   }
   public void formatChecker(String emailBody){
      System.out.println("Format Cheking on :: " + emailBody);
     
   }
   

   public void applyFilter(Consumer<String> composeFilter,String emailBody){
      composeFilter.accept(emailBody);
   }

   public static void main(String[] args) {
      EmailManager manager = new EmailManager();
      String body ="This is a mail from Javaonfly";
      Consumer<String> filter = manager::spellChecker;
      Consumer<String> composeFilter = filter.andThen(manager::grammarChecker).andThen(manager::formatChecker);
      manager.applyFilter(composeFilter, body);
     
   }

}




Conclusion : Consumer has multiple utilities you can use it for crisp coding and use of Method reference along with java8 defined interface we can rewrite our OOPs design pattern in a shorter and crisp way , but as now behaviour stuffed in methods, Its breaks the SRP, because all the methods now in one class and class has many reason to change.