Java8: Oogways final advise on Optional

Master Oogways enlighten us about Optional in his previous two sessions, and Now he set the stage for the final advise on Optional and believe me that is the most searchable questions on the internet about Optional, also many peoples mailed in OpenJDK forum regarding "Why Optional is not Serializable?" , Oogways promises to PO that he will try to give the best possible answers and we all keen to know the answer from Oogways as he is the wisest master in the world.
Let see the conversation happened beet ween PO an Oogways.

PO: Master I try to figure out why Optional is not serializable also searched on the internet but not found any compelling answers can you please enlighten me?
Master gives a calm look to Po and start his speech
Oogways: Before starting why Optional is not serializable I want to talk about an upcoming project in jdk10 which is Project Valhalla.
Project Valhalla: The slogan of project Valhalla i“Codes like a class, works like an int!” -- so, project Valhalla try to create a new user-defined datatype which can be treated as class i.e you can have data and behaviours tied into this but when that datatype runs on JVM it will act as primitives , i.e this datatype not stored in heap memory unlike Object and it does not have reference it will act as primitives like int, float -- it will stores in the stack memory. So obvious question comes
why so?
what are the benefits of that new datatype?
To answer this question we have to know a concept of ValueObject-- In Java sometimes we design some Objects which just carry value do nothing else-- act on the value, or preserve the state, this Object does not have any identity think about Integer what it does it wraps a primitive int value and why it is created?-- Just to support
java collection framework, It just a Wrapper Object, think about the ValueObject pattern in JEE or a Money Object(Value and currency), these are  used to pass values so conceptually these objects are not a proper object by definition, those objects are immutable in nature , and two objects are equals if their values are equal no identity check and obviously does not preserve a state which is the crux of an Object it acts as primitives more than Object so we called the Value Object, Now we all know there is cost associate to create Object, Even to make an Integer from int , it has to create a header(8-16 byte) and reference(4-8 bytes) in case of a reachable object, so instead of 4 bytes it takes 4+8+4=16 bytes minimum. also in case of the array of Integers, it has to traverse through pointers to fetch value as Integer array stores the references, not the value but in case of primitives it will store value locally in the stack so traversing is very fast, So the concept Project Valhalla it treats value type as primitives it gives us to create user-defined primitives.
Now I will tell you something about serialization.
Serialization: Serialization is a technique by which one can store the Object state in form of the stream so in future, we can reconstruct the state of the Object in same or another JVM from the stream. To achieve serialization is not a problem but Serialization has a huge maintenance cost, Because when we make an Object serializable we have to take care of the following
Back and forward JVM support: The Key feature of a serialization is it would be supported across any versions of Java including current and future release, so if an Object serializes in Java8 should be deserialized in java1.4 and vice versa so it supports backward and forward compatibility.So it has huge maintenance cost as various scenarios can occur where it may be broken, think about a situation if you want to add a new HAS-A relationship in your serializable Object and that class has been introduced in upper version of JDK how it would be deserialized in lower JVM as lower JVM does not know about that class.  Also in case deserializing it needs back-references to reconstruct the graph and need the Object reference. So Serialization hindering further modification of the Object, so maintaining Serialization is not a cup of tea.

Now, I come to the point why the Optional is not serializable, PO, If you look about the Optional it just wraps a value so it is a boxed class, If two Optional value is same we can say those are equals, so it treats like a Value type even in JavaDoc of Optional says
"This is a value-based class; use of identity-sensitive operations (including reference equality (==), identity hash code, or synchronization) on instances of Optional may have unpredictable results and should be avoided."
so it is clear Optional is a Value type and they know the Project Valhalla is in roadmap so obviously, they want to change Optional to a Value type (Identityless) when Project Valhalla onboard. And if they make them Serializable, now it needs to reside in heap memory and to deserialize the same need a reference but Project  Valhalla remove them from heap and stores in the stack so the question is how you deal with the same. there are lots of If and buts so they don't confident enough to make it serializable.
Another thing is the motto of Serialization is to reconstruct the state but Optional is a Valuetype and stateless so why they make it serializable it does not meet the criteria of serialization. Those are the reasons to not makeOptional serializable.
PO : I understood the Objective of not making Optional serializable but if they make it value type and make it serializable both by following technique, Suppose they make Optional as value type so it does not have any reference, but in the case of de-serialization  we can box them in an Object and make it present on heap memory, so it will be dubious nature, by default it is a value type but in case of deserialization it will act as an Object, by this we can solve the problem.
Oogways: PO, I like your thought, it proves that why I choose you as a Dragon Warrior. Really it is a compelling idea but think Optional is a Value type and in case of deserialization you want to make footprint in heap at that point it breaks the purpose of value type, To support serialization we unnecessary breaks the principle of project Valhalla, and bring back the problem which project Valhalla tries to solve, Optional is the category of Value Object to make it dubious nature to just support serialization is just a lame idea to me, To carrying the cost of serialization should have a compelling use cases, I don't see anything comelling in case of Optional.
PO: I understood master, Thanks for giving me a new direction I will learn more about project Valhalla and value type.
Oogway: Well, I am planning to give a session on Project Valhalla, you can attend that session.
PO: yes Master, I will and I bring my friend Shamik with me.
Oogways nodded his head.

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.