Java 8, 9, 10, 11 and beyond delivering new features to the JDK. JDK 8 had come up with so many new features like lambda expression, functional interface and so on. But post that Java 9 got released in 2017 with a very big change that is the introduction of modularity. Then after one year of Java 9, Java 10 got released in the year 2018 with some new features and some enhancements of local variable type and garbage collection. JDK 9 and JDK 10 are feature releases of Java. Feature release means we will get only two scheduled updates. Java 11 got released in 2018 where java has open-sourced some of its closed sourced parts of JDK through OpenJDK release. JDK 11 also has removed so many packages from it like Applets, JavaFX, Web start, etc.
Now Oracle has come up with a new release Model, that every 6 months there will be a release of a new major version of JDK. As the number of major releases of java will get increased, because of this Oracle, will not be providing long-term support for all the releases. Oracle has come up with a plan that only one Long term support release every three years. They have classified JDK 8 as an LTS (Long term support) release. But for commercial users (JDKs 8 usage in production), JDK 8 public updates stopped in Jan 2019. But for local usage, i.e. for noncommercial usage, JDK 8 public updates will be available till Dec 2020.
Overview of Software Design:
Now let’s discuss some of the key features of all the latest versions of Java starting from JDK 8 till JDK 11. So, I will give a brief overview of all the main features of all the JDKs versions but the detail technical explanation of each features with programmatically explanation will be published in our coming blogs. Just go through the below concepts of the features of Java 8, 9, 10 and 11 for getting a better clarity on each feature and its usage.
Java 8 Features:
The below new features have been introduced in JDK 8:
This is a powerful feature in Java 8 using which we can write a few lines of code and do a lot of work. The main goal of lambda expression is to introduce the benefits of functional programming to Java. A lambda is an anonymous function in Java. That is, a function which does not have a name, return type and access modifiers. Lambda expressions are also known as the anonymous functions or closures.
Another example here with two parameters here:
If the compiler can derive these data types, then we do not need to specify the types. (a,b)-> SOP (a*b);
There are various advantages of lambda. Using few lines of code, we can do a lot of work in java. And it is easy to implement anonymous inner classes. Also, we can pass lambda expressions as parameters to other methods which is very powerful as well. To implement lambda in Java 8, Java 8 introduces Function interface. We need to use functional interfaces to express lambdas.
If an interface has one and only one abstract method, then it is called as a function interface. And that abstract method is called a functional method. Example of inbuilt function interfaces are Runnable interface which has the run () method i.e. an abstract method. Another example is a Comparator interface in java which has the compareTo() abstract method.
Starting Java 8, we can also add default methods to the interfaces which I am going to explain in this blog also. We can define any number of default methods in a functional interface but there should be one and only one abstract method. Java 8 also provides us with an annotation called @FunctionalInterface. If we mark our interface with this annotation, then we can only define one abstract method in that interface. Here Compiler will raise error if we try to add more than one abstract method. Functional interface is required to implement lambda expression.
Starting from Java 8, we are allowed to have default method implementations inside interfaces. We have to use the “default” keyword to create a default method. We can override our default method in our child classes, or we can use the default implementation if we do not want to override.
Here we have overridden the default method m1() in our child class. So, the output of the Test class if we run will be “m1 inside B”
A predicate is a function with a single argument, and it returns a Boolean value. To implement a predicate, we have to use the Predicate interface introduced in Java 1.8. It is a functional interface with only one abstract method that can take in any type of argument, but as I said it always, should return a Boolean value.
Since it is a functional interface, we can express it as a lambda expression.
We can use predicate when we have the requirement to evaluate a condition to filter similar or collections of objects.
Using Streams, we can process the data in a declarative manner very similar to that of SQL. It makes very easy for us to process the data or objects inside a collection. These streams are not the same as java.io.streams, which meant for reading/writing files.
The Stream interface introduced in Java 8. The stream is an interface in java.util.stream package. We can get a stream on a collection by invoking the stream() method, which added to the Collection interface in java8. Once we have a stream to process the collection, we will do it in two steps.
The first step is configuring the stream. We can do the configuration in two ways. Filtering, wherein we invoke the filter() method, pass it a predicate which will evaluate into a Boolean expression as you already know what a predicate is. The object of the collections will be filtered out based on the predicate. Syntax of the Filter method is:
Filter() method will return, the stream which has the filtered-out object. The second way of configuring is using a map method. The map method on the stream again returns a stream, but this time it does not take a Boolean expression. But it takes a function instead.
This method will create a new collection or a new object for every object in the collection. So if you want to suppose if you have a requirement wherein you have to create a new set of objects or new sets of collections based on the input, then you will use a map. It will map each input to a corresponding output object. If you simply want to filter, then you use the filter method.
The second step is “Processing.” i.e., to process the data itself. The stream API provides various methods such as collect, count, sorted, min, max, etc. to process the data.
Java 9 Features:
Java 9 offers many cool features, with many additions to existing features.
Starting Java 9, we can define private static as well as methods inside an interface. And these private methods will be used by the default method in the interface.
Try with resource block was introduced back in Java 6. But we had to define all our resources to try to work within the front bracket. But Starting Java 9, we can define those resources anywhere in our code before the try block, and we can directly use those objects or resources inside the try. It is an enhancement made to try with resource block.
There are several enhancements made to the Streaming API. The new thing is that Java 9 brings in "Modules" which is a great way to code and configure your application. It also brings in http2 client, which makes it easy to make HTTP calls or restful calls from our java code.
In java 9, Linking is a great concept towards microservices app development. Using Linking we can link only those libraries that are required, for our application to work instead of bringing everything inside the JDK or a particular library, we can link only those libraries that are required for our application to function.
Java 9 introduces JShell. It gives us a Shell type environment of our own where we can type in our java snippets.
Instance Private Methods and Static private Methods in Interface:
Starting from Java 9, we can create private methods in an Interface and can also use that private method inside of the default methods so that they can reuse certain functionality i.e, common across them.
The private methods inside our interfaces can also be static. The use of the static method is when one of the default methods is, static then in that, the case if we have to call the private static method from the static default method.
Improved try with resource Blocks:
The try with resource block which was introduced in Java 1.6, in that we cannot use the resources that defined outside this try with resource block like below:
It will give you an error. But starting from java 9, we can define our resources anywhere in our code which are auto closable then we can use them directly in the try block like the below:
Before java 9, if we want to create an immutable Sets, Lists, and Maps i.e. immutable collections, then we have to create that collection first and then pass that collection to the “Collections.unModifiableSet/List/Map() “ methods which are a long process. Java 9 simplifies things for us like below:
Before Java 9, we could use the safe variable arguments annotation only on static methods and on final methods and not on Private methods. Starting Java 9, we can use this annotation on Private instance method as well.
New Methods in Streaming API:
The streaming API that was introduced in Java 8 gives us great way to manipulate collections. Java 9 introduces more methods to the streaming API. It enhances the streaming API methods like “takeWhile()”, “dropWhile()” and a static method called “ofNullable()”.
Another cool tool that was introduced in Java 9 is the Java Shell or the J Shell. JSHELL is a REPL tool which stands for read, evaluate print and loop. Without creating any java classes with main method, we can quickly start typing our java code and see the output of it. Under your JDK, if you go to the bin folder then you will find jshell. You can use it directly from your terminal window and type in Jshell. Then you can enter into jshell mode and try and test your java code.
Modules In Java 9:
Java 9 introduces java platform module system. A module is a bunch of packages. It is just like a jar file except for it comes with a module-info.java. So, every module we create will have a module-info.java which can use two different things inside it i.e. a “export” and “requires”. These two offers a lot of advantages over a jar file. So, using export we can say which packages inside this module we want to expose out to which other modules. Using “requires”, we can depend on another module.
We have to specify what other modules packages this module needs. It was not possible in case of a jar file. Using modules we can specify what all are required right before the application runs so that the JVM will check if everything and then only it starts the app. So, using modules we can get rid of “noClassDefFoundError”.
With modules, we can exactly specify which version of the dependency we want. In Jar file, everything is public, whatever is there in a Jar file. We cannot restrict. But modules give us additional security where we can tell which functionality within this module should be exposed out to which another module. In earlier Java, they have rt.jar which, have all the dependencies, but now in java 9, they have split them across the modules.
When we are exposing out or exporting certain packages from within a module, we can qualify them at the end so that they are available only to certain modules we want and not to the other ones.
Java 10 Features:
There will be releases every six-month going forward. Earlier before java 10, there used to be released once every three years or two year.
Using Var keyword to declare variable:
In java 10, if we want to declare an integer variable or a float variable then, we do not use to specify the type, and simply we can use the “var” keyword and can assign the value. Ex:
var is an inferred type. If we define the variable using the var keyword, the compiler will infer the type. If after assigning one value to x here and then if you want to again assign a different type like x=”xyz”, then the compiler will throw an error. But this “var” is not a keyword actually because in java if you create a variable name as “var” then it will not show any error. This is for backward compatibility java has made like this.
Collectors API changes:
Java 10 has come up with some enhancements in the Collectors APIs. Suppose I will explain with an example. Suppose we will create a list of integers using List.of() method like below:
Now suppose we want to filter out all the values inside the list which are multiples of 3. So, we can use List
But if we want to restrict this newList so that we cannot do [newList.add(30)]. There were no such restrictions before Java 10.
So, to make a list unmodifiable, then in Java 10, Collectors have a new method called “toUnmodifiableList or set or map. So, we can write our code like the below:
Java 11 Features:
Java 11 shows the advantage or the power of frequent small releases. We as, a full stack Java developer, now need to master only a few features at a time, but the features are very good. The first two features revolve around Strings, and then we have a feature on the optional class, then some deprecations and removals.
String API Updates:
IsBlank() method: This has added to the String class. If a Java String has any number of blanks inside it then, this method will return true. Even if the String contains a single blank (white space) also (String str=” ”); then, the isBlank() method will return true. If the string has at least one character with any number of blanks (white spaces), then the method will return false. So, the new IsBlank() method helps us with the blank Strings.
Lines(): This new method in Java 11 returns a stream of Strings by splitting the string using the new line character when the string has a new line character inside it. For Ex.:
As the lines() method returns a stream so we can write our code using Collector like below:
So, the output we will get is: [I, am, the, creator of this Blog]
So here the lines method returns a stream of Strings which we are putting into a list. The lines method splits the string wherever the new line character is present.
Strip method(): The existing trim method does not have Unicode support. Suppose I will append a white space in Unicode (“\u2000”) to a String, then the trim method cannot remove the white space.
So, to remove the Unicode white space, java 11 introduces a new method called strip() which, removes the Unicode white space. There are two variations of strip method i.e, “stripLeading()” method and another one is “stripTrailing()”. So, these two methods are for removing leading white spaces and trailing white spaces, respectively.
Repeat() method: So, java 11 introduces repeat() method. If we want to repeat a particular string for n number of times, then we can use this repeat () method. Ex: System.out.println(“-“.repeat(100));
It will repeat the “-“character for 100 times and will print in the output console.
File API Updates:
Java 11 makes it super easy to read and write strings to and from a file. File has the “WriteString()” method which takes a path as input that is the file path and their character sequence i.e. nothing but a string of characters that want to write in a file. This method returns a file path where the file gets created. For Ex:
So here this, “writeString()” method returns a path on which the file created to which it will write the content in a single line.
Now for reading the contents of that file, java 11 provides another method called “readString()” which read the contents of a file and returns the String.
IsEmpty() method on Optional Class:
Java 11 also provides isEmpty() method on Optional class. It is very useful when you are working with reactive programming when you work with spring. Where when it returns an Optional type, then we can check if it is empty using the isEmpty() method.
The above line will create an empty optional String. Before java 11, if you have to check in the above line if the “str” variable has a string inside it or not, we will have to use the “isPresent()” method to see if the str variable has the string value inside it.
Now in Java 11, we have isEmpty() method for this. Now if we have to execute certain logic on the basis of the str variable has some value or it is empty then we can directly use this “isEmpty()” method. In our case “str.isEmpty()” will return true. So, in another example below:
//This will return false as the str variable is not empty. it contains the string “mano”.
Deprecations and Removals:
Like every other version, there are some deprecations and removals in Java 11. Java 11 has removed certain packages like java.xml.ws, java.activation, java.transaction, java.xml.bind and java.corba. All these packages and classes were part of the JDK earlier. All these were deprecated in an earlier version of java bit in JAVA 11 they are completely removed. So, your code will not compile if you are using any of these if you are relying on JDK. But if you have a maven project then you can grab these dependencies from the maven repository, and you can still use them. But these are no longer part of JDK in Java 11.
Here I have explained the most important features of JDK 8, JDK 9, JDK 10, and JDK 11. The theoretical functional overview I have given through this article. So you can study, each new feature or enhancement of the latest JAVA in your Eclipse or IntelliJ or any IDEs, to get more clarity on the aspects of Java programming usage of this feature.