Sunday, April 21, 2019

Java 10 - Local Variable Type Inference


Java 10 - Local Variable Type Inference

In one of my previous blog, I have already discussed about Type Inference. If you don’t have the idea about Type Inference then you can check my blog here.

If we want to understand Type Inference in one line then we can say that It is the capability of the compiler to automatically detect the datatype of a variable at the compiler time.

What is Local Variable type inference?

Java 10 added new feature that allows the developer to skip the type declaration associated with local variables (those defined inside method definitions, initialization blocks, for-loops, and other blocks like if-else), and the type is inferred by the JDK. It will, then, be the job of the compiler to figure out the datatype of the variable.
Until Java 9, we had to define the type of the local variable.

E.g.: String message = “Welcome to Waheedtechblog.com”;

The above statement is right as that’s how things have been since the inception of java but if you observe, the type of the object at right side is clearing mentioning the type of data that we have defined at left side which makes the variable redundant.
So with Java 10, We can declare a local variable without defining its data type at left side.

            Var message = “Welcome to Waheedtechblog.com”;

Over here, we don’t have to provide the data type of String to local variable message. Compiler will get the datatype based on right hand side value.

Note:
  • This feature is available only for local variables with the initializer. It cannot be used for member variables, method parameters, return types, etc as the initializer is required as without which compiler won’t be able to infer the type.
  • To support backward compatibility, var is not a java reserved keyword. So, we can create variable with name var as it is allowed.

Let’s see where all we can use var

package com.waheedtechblog.typeinference;

import java.util.function.BiConsumer;
import java.util.function.Consumer;

public class TypeInferenceExample {

       static {
             // static block variable
             var staticVaribale = "var in static block";
             Consumer<String> displayOnConsole = msg -> {
                    System.out.println(msg);
             };
             displayOnConsole.accept(staticVaribale);

       }

       public static void main(String[] args) {

             TypeInferenceExample inferenceExample = new TypeInferenceExample();

             BiConsumer<String, String> displayOnConsole = (str, msg) -> {
                    System.out.println(str + msg);
             };

             // Before Java 10
             String message = "Welcome to Waheedtechblog.com";
             displayOnConsole.accept("Before JDK 10: ", message);

             // Using JDK 10, Local Variable
             var message10 = "Welcome to Waheedtechblog.com";
             displayOnConsole.accept("With JDK 10: ", message);

             // local variable declaration in enhanced loops
             String[] countryName = { "India", "Japan", "UAE", "USA", "UK" };
             displayOnConsole.accept("", "List of Country using enhanced loop");
             for (var country : countryName) {
                    displayOnConsole.accept("", country);
             }

             // basic for loop
             displayOnConsole.accept("", "List of Country using basic loop");
             for (var i = 0; i < countryName.length; i++) {
                    displayOnConsole.accept("", countryName[i]);
             }

             displayOnConsole.accept("Length of string '" + message10 + "' is: ",
                           String.valueOf(inferenceExample.getLenth(message10)));


             // var is not keyword, so you can create variable with name var as well.
     String var = "var is not keyword";
     displayOnConsole.accept("", var);
       }

       // can return var type as well
       private int getLenth(String msg) {
             var length = msg.length();
             return length;
       }

}

Output:
var in static block
Before JDK 10: Welcome to Waheedtechblog.com
With JDK 10: Welcome to Waheedtechblog.com
List of Country using enhanced loop
India
Japan
UAE
USA
UK
List of Country using basic loop
India
Japan
UAE
USA
UK
Length of string 'Welcome to Waheedtechblog.com' is: 29
var is not keyword

Illegal use of Var:

1.    Can’t use as a class field
Class Test {
            Var msg; // not allowed as it is local variable inference
}
2.    Local variable without initialization
Private void getOTP(){
            Var otp ; // cant use without initializer
}
3.    Not allowed as parameter for any methods
Private void getOTP(var secretKey){
            //Error, cannot use var on method parameter
}
4.    Not permitted in method return type
Private var getOTP(String secretKey){
            //Error, Method return type cannot be var
}
5.    Not permitted with variable initialized with ‘NULL’
Private String getOTP(String secretKey){
            Var msg = null; Error, cant initialize as null
}

You can download the source code from my GitHub repository.

Happy Coding..!!!









Saturday, April 20, 2019

Java 8 - Optional


Java 8 - Optional

In this blog, I’ll discuss about Optional class which was introduced in JDK8 under java.util.package. Optional class is used to represent a value is present or absent.

With Optional class, developers have to less worry about NullPointerException and can work on neat and clean code. It contains at most one value.


Advantages:
· No need to check for null
· No more NullPointerException at runtime

Public final class Optional<T> extends Object {
}
Let’s understand all its usage with the help of example

1. Optional.empty()

To create an empty Optional object we simply need to write

// How to create empty Optional
             Optional<String> optional = Optional.empty();
             System.out.println("1. Optional: " + optional);
    Output:
            1. Optional: Optional.empty


2. isPresent()

You can also check whether any value present in Optional or not
          System.out.println("2. Optional: " + optional.isPresent());
Output:
          2. Optional: false

3. Of() method

We can also use Static Of method to create an Optional Object.
      //Can create Optional using Static Of method
      Optional<String> name = Optional.of("WaheedTechblog.com");
      System.out.println("3. Name: " + name.toString());
Output:
       3. Name: Optional[WaheedTechblog.com]

Note: Make sure you are not passing any null value to Of() method else it would throw a NullPointer Exception.

Optional<String> nullValue = Optional.of(null);
             System.out.println("4. Name: " + nullValue.toString());
Output:
             Exception in thread "main" java.lang.NullPointerException
       at java.base/java.util.Objects.requireNonNull(Objects.java:221)
       at java.base/java.util.Optional.<init>(Optional.java:107)
       at java.base/java.util.Optional.of(Optional.java:120)
       at com.waheedtechblog.optional.OptionalExample.main(OptionalExample.java:20)

4. OfNullable()

If you are not sure about the object you must use OfNullable API.

       //Can accept NUll value as well
       Optional<String> isNull = Optional.ofNullable("WaheedTechblog.com");
       System.out.println("5. Name: " + isNull.toString());
Output:
       5. Name: Optional[WaheedTechblog.com]

If we pass a null reference, it does not throw an exception but returns an empty Optional object.


5. isPresent()

We can use isPresent() method to check whether the Optional object is empty or contains some value.

Optional<String> isNull = Optional.ofNullable("WaheedTechblog.com");
       //check isNull object contains some value
       if(isNull.isPresent()) {
                    System.out.println("6. Optional object contains some value: " + isNull.toString());
             }
Output:
       6. Optional object contains some value: Optional[WaheedTechblog.com]


6. isEmpty()

Similarly , we can use isEmpty method to check whether the Optional object is empty or not

//Check whether object is empty or not
             Optional<String> nullValue = Optional.ofNullable(null);
             if (nullValue.isEmpty()) {System.out.println("7. Is Optional empty? " + nullValue.toString());
       }
Output:
7. Optional object contains some value: Optional.empty


7. ifPresent()
It enables us to run some code if Optional Object is not empty. Most of the time, we normally do something like this in our application.
 If(user != null) {
       String name = user.getName();
}
Over here, we are performing some operation based on if condition. This approach is lengthy and there are chances to miss such null checks which can result in a NullPointerException at runtime.

ifPresent() accepts Consumer functional Interface.

//Execute if Optional object exist.
             Optional<String> name = Optional.of("WaheedTechblog.com");
             name.ifPresent(value -> System.out.println("8. Length of name: " + value.length()));
Output:
8. Length of name: 18


8. orElse()

We can use orElse() method to set some default value incase if Optional object is Empty.

      //Set Default value if Object is empty
             String nullString = null;
             String testOrElse = Optional.ofNullable(nullString).orElse("This is default value");
             System.out.println("9. Print testorElse value: " + testOrElse);
Output:
9. Print testorElse value: This is default value


9. orElseGet()

This API is very similar to orElse() method except that instead of taking default value, you can pass Supplier functional interface which returns response based on some operation.

//Invoke Functional Interface if Optional Object is empty
String testOrElseGet = Optional.ofNullable(nullString).orElseGet(() -> "waheedtechblog");
             System.out.println("10. Print orElseGet value: " + testOrElseGet);
Output:
            10. Print orElseGet value: waheedtechblog

Note: At the very first glance, it looks like orElse and orElseGet method are very similar and either one of them can be used to get the default value but this is not very true. There is a subtle but very important difference between the two.

Let’s understand this with Example
       private String getDbConnection() {
             System.out.println("13. Invoking Default fucntion");
             return "Create db Connection";
       }

// Checking the diff between orElse Vs orElseGet
String testOrElseDiff = Optional.ofNullable("waheedtechblog").orElse(optionalExample.getDbConnection());
             System.out.println("11. Print testorElse value: " + testOrElseDiff);

String testOrElseGetDiff = Optional.ofNullable("waheedtechblog").orElseGet(optionalExample::getDbConnection);
System.out.println("12. Print orElseGet value: " + testOrElseGetDiff);

Output:
13. Invoking Default fucntion
11. Print testorElse value: waheedtechblog
12. Print orElseGet value: waheedtechblog


If you observe the output, you will realize that orElse() method is invoking getDBConnection() when the object is already present whereas orElseGet() method is not invoking the DB call.

So, I would suggest choose orElseGet over orElse as database query or any rest API call can cost to your application performance when there was no need of that.

10. orElseThrow()

Instead of calling any default method in case of Optional value not present, it throws an exception.

//Throw runtime exception if Optional value is not present
      String orElseThrowTest = Optional.ofNullable(nullString).orElseThrow(RuntimeException::new);
Output:
Exception in thread "main" java.lang.RuntimeException
       at java.base/java.util.Optional.orElseThrow(Optional.java:408)
       at com.waheedtechblog.optional.OptionalExample.main(OptionalExample.java:62)

11. get()

Get returns the value of Optional Object if not null or else throws no such element exception.
Optional<String> getTest = Optional.ofNullable("waheedtechblog");
      System.out.println("15. GetTest value: " + getTest.get());
Output:
        15. GetTest value: waheedtechblog

Note: get throws NoSuchElementException if Optional object is empty


12. Filter()

The concept of filter is very similar to stream API filter. It takes Predicate as an argument and returns an Optional object.

// filteration on Optional
             Optional<String> username = Optional.of("waheedtechblog");
boolean isLengthValid = username.filter(str -> str.length() > 5).isPresent();
             System.out.println("16. is Length Valid: " + isLengthValid);
 Output:
       16. is Length Valid: true

13. map()

Using map, we can transform the Optional value.

        // map to perform operation on Optional
        Optional<String> password = Optional.of("waheedtechblog");
        String encodedPassword = password.map(str ->                                  Base64.getEncoder().encodeToString(str.getBytes())).get();
System.out.println("17. Encoded Password: " + encodedPassword);

              Output:
            17. Encoded Password: d2FoZWVkdGVjaGJsb2c=


We can also merge filter and map together to get the result.

       // first do validation and then operation on Optional object
       String validatedEncodedPassword = password.filter(ps -> ps.length()
> 15)  .map(str ->  Base64.getEncoder().encodeToString(str.getBytes())).toString();
System.out.println("18. Validated Encoded Password: " + validatedEncodedPassword);

Output:
18. Validated Encoded Password: Optional.empty

Happy Coding…!!!