Advanced Java Features

With every release of Java, there are new features and API's that are introduced. In this short lesson, you will see some important new features that you may wish you familiarize with that were added in Java 8 and Java 9

Java 8 Features

Lambda Expression and forEach

forEach method on collection was added to help in iterating the collection. In this example you will see both forEach and Lambda Expression usage.

Lambda expressions have been around in other programming languages like Python for a while and in version 8, Java also introduced the use of Lambda expressions

Lambda expressions replace method definitions when ever the method is a simple expression that returns something. However, note that the lambda itself should not have a 'return' keyword but implicitly the expression will return the result of the expression. Lambdas are convenient in filters when applied on collection. Let us take a an example:

Syntax of a Lambda: (optional-argument-list) -> {typically one statement but can have more than one also }


import java.util.ArrayList;
class LambdaExample{

    public static void main(String[] args){

        ArrayList<String> names = new ArrayList<String>();
        names.add("APPLE");
        names.add("ORANGE");
        names.add("PINEAPPLE");

        names.forEach((name)->System.out.println(name.toLowerCase()););

        System.out.println(names);
    }
}

In the above example the lambda expression is passed in to the forEach method of the ArrayList. The Lambda Expression is

(name)->{System.out.println(name.toLowerCase());}

This expression takes one argument, name and has one statement in its body System.out.println(name.toLowerCase()); This expression is applied to every element of the ArrayList with the above invocation.

Since there is only one statement inside the body of the lambda, we could have removed the curly braces and in that case the statement becomes

names.forEach((name)->System.out.println(name.toLowerCase()));

Points to note

Body of the Lambda cannot have a return statement

Lambda with Functional Interface

An interface that can have only one and only one abstract method is called a Functional Interface. To ensure that more than one method cannot be added, @FunctionalInterface annotation is used.

A lambda expression can be used instead of creating Anonymous class for implementing a functional interface and here is an example:


public class LambdaExample2 {
    public static void main(String args[]) {
        int x = 5;
        int y = 10;

        Area rectArea = (int a, int b)->a*b; // lambda expression to define the calculateRectangleArea method
        int ans = rectArea.calculateRectangleArea(x, y);
        System.out.println(ans);
    }
}
@FunctionalInterface
interface Area {
    int calculateRectangleArea(int length, int breadth);
}

Method Reference

Instead of using Lambda, you could also use methods of class as the implementation methods for a functional interface. Here is an example


class MethodReferenceExample {
    public static void main(String[] args) {
        Area area = MethodReferenceExample::calculate;  // static Method reference
        int value = area.calculateRectangleArea(10,20);
        System.out.println(value);
    }
    static int calculate(int a, int b){
        return a*b;
    }
}

@FunctionalInterface
interface Area {
    int calculateRectangleArea(int length, int breadth);
}

You can also use an instance method instead of a static method in which case you just instantiate the object and then reference the method as given below


class MethodReferenceExample {
    public static void main(String[] args) {
        MethodReferenceExample mre = new MethodReferenceExample();
        Area area = mre::calculate;
        int value = area.calculateRectangleArea(10,20);
        System.out.println(value);
    }
    int calculate(int a, int b){
        return a*b;
    }
}

@FunctionalInterface
interface Area {
    int calculateRectangleArea(int length, int breadth);
}

You can also implement the interface method through a constructor and in that case you use the 'new' keyword instead of the method name. The same example is shown below with the implementation being in the constructor;


class MethodReferenceExample {

    public MethodReferenceExample(int a, int b) {
        System.out.println(a*b);
    }
    public static void main(String[] args) {
        Area area = MethodReferenceExample::new;
        area.calculateRectangleArea(10,20);
    }
}

@FunctionalInterface
interface Area {
    void calculateRectangleArea(int length, int breadth);
}

default and static methods can be added in an interface

Refer: https://ebooks.mobibootcamp.com/java_android_journey_1/interface_and_polymorphism.html

Optional Object Introduced

For a long time, handling NullPointerException has been an area where many developers have come up with multiple strategies. When you call any method on a null object, you get NullPointerException.

Java 8 introduced the Optional object to mainly help in handling null values. You create an Optional object by passing in any variable. If the value passed in is null, then, you can find that by calling isPresent method on the Optional object. Here is an example:


public void myMethod(String name){
        Optional opt = Optional.ofNullable(name);
        if(opt.isPresent()){
            System.out.println(" Hey welcome " + opt.get());
        }
    }

In the above example if the name is null, it does not go into the 'if' block. If not null, then you can use the get method on the optional object to get the value that the 'name' variable was holding.

Date

The Date() class was the standard class to use for all Date related functionality until newer classes were introduced in Java 8. From Java 8 onwards you can use LocalDateTime to represent date/time information and to represent date/time as per the time zone, you can use ZonedDateTime

Here is an example:


import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Set;

public class DateExample {

    private static final String DATE_TIME_PATTERN = "MM/dd/yyyy HH:mm:ss";

    public static void main(String[] args) {

        Set<String> zones = ZoneId.getAvailableZoneIds();
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter format = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);

        ZonedDateTime currentTimeZoned = ZonedDateTime.of(now, ZoneId.of("EST", ZoneId.SHORT_IDS));

        for (String s : zones) {
            ZoneId zone = ZoneId.of(s);
            ZonedDateTime timeInAnotherZone = currentTimeZoned.withZoneSameInstant(zone);

            System.out.println("Current time in zone " + s + " is " + timeInAnotherZone.format(format));
        }

    }

}

References:

Example with Date

To convert a given String to Date and vice versa, you can use SimpleDateFormatter as shown below


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateExample {

    private static final String DATE_TIME_PATTERN = "MM/dd/yyyy HH:mm:ss";

    public static void main(String[] args) throws ParseException {

        SimpleDateFormat formatter = new SimpleDateFormat(DATE_TIME_PATTERN);
        Date date = formatter.parse("04/03/2021 12:00:00");
        System.out.println(date);
        System.out.println(formatter.format(date));

    }

}

Java 9 Features

Interactive Shell

Interactive shell has been around; e.g., Python and now it is great that Java 9 introduced interactive shell for Java also with version 9!

To test out simple statements and regex, this is a great tool. No need to create a .java file and then compile that to .class file to run the program. Just open the interactive shell from the command line with

jshell

and put the statements one at a time and hit return on the keyboard. Each individual statement will be executed with the results dumped on the console. To exit the shell, use Crtl+D

Private Methods in Interface

By default all method declarations in an Interface are public and so the default method that was introduced in Java 8 is no expection. However, in Java 9 you can now declare a private method that can be used inside the default method.

Note that the private methods are not visible to any of the implementing class and this method can only be used by other private methods or default methods.

Modules

Module basics

package-info.java

Have you noticed a file called package-info.java when ever you create a new package in Java 9 or higher version of Java?

Let us understand that now:

package-info.java was introduced in Java 5 and it takes the place of package.html file. As you know you can create the documentation for all your classes using the javadoc tool in JDK. This file generates documentation for the package.html file.

If this file is present, when you run the javadoc tool, it looks for documentation related to package level annotations and comments. For e.g., if you want to deprecate all the classes in the given package, you could add @Deprecated annotation right above the package line and that would mark all the classes in the package as deprecated.

The only thing that this file should contain is the package declaration and any annotations or comments for Javadoc.

results matching ""

    No results matching ""