Comprehensive Notes For Java 8 Features Every Developer Must Have
Java SE 15 was released in September 2020 with a bundle of features but still, Java 8 features are one of the most important ones.
Recently Java SE 15 was released on September 2020 with a bundle of features. It is likely to get a new version again in March 2021 as per the official blog by Oracle. But still, March 18, 2014, is embarked as one of the most important days in the history of Java as version 8 was released. The features of version 8 changed the way developers code in Java. Even today, a Java developer is asked about the features of Java 8.
Disclaimer: Oracle no longer provides free support for Java 8. AdoptOpenJDK will provide free public updates for their version of Java 8 until at least September 2023, Oracle has already dropped free support for their JDK. Hence, a new Java developer must start with OpenJDK 11.
This was the most anticipated feature of Java 8. But why? Simply because of the fact that it made Java more closer to functional programming. Functional interfaces had been introduced in Java 8. The interfaces having just one abstract method is a functional interface.
@FunctionalInterface annotation is added so that we can mark an interface as a functional interface.
In the above example, you can see that LambdaExample class uses an interface WishingInterface having one abstract method. If the interface is annotated with
@FunctionalInterface annotation and we try to have more than one abstract method, it throws a compiler error.
Lambda expressions enable Java’s object-oriented programming world with functional programming. It provides an implementation of an interface which has a functional interface. When lambda functions are used, we don’t need to define the method by providing the implementation. In fact, lambda expressions are treated as a function.
The basic syntax of Lambda expression is (argument) → (body)
As mentioned earlier, prior to Java 8, there was no way we could use functional programming in the strictly object-oriented world. We had to create anonymous inner class objects or implement interfaces like Runnable, ActionListener, Comparable which are some of the examples of functional interfaces.
From Java 8 onwards, we can simply use the instance of the functional interfaces using lambda expressions.
@FunctionalInterface states the JVM that the interface can have only one abstract method. A functional interface can have any number of default methods.
default methods in Interfaces
Traditionally interfaces used to have only abstract methods to achieve abstraction in Java. Abstract methods are needed to be defined in the implemented classes. After Java 8 release, default methods are added to interfaces to add extra features to current interfaces without disrupting the current implementations.
For example, stream() is a default method added to Collection interface. Had stream() would have been added as an abstract method, all the classes implementing Collection interface had to define stream() which would have irked developers. Since stream() is a default method, all the classes implementing Collection interface inherit the default implementation.
Default Methods Can Cause The Diamond Problem
Yep. It can happen. Abstract classes and interfaces have become quite similar now. Both can contain abstract methods and methods with implementations, although the syntax is different. There still are some differences (for instance, abstract classes can have instance fields, whereas interfaces cannot), but these differences support a central point: since the release of Java 8, we have multiple inheritances (via interfaces) that can contain code.
Inheriting from different interfaces multiple default methods with the same signature and different implementations is a problem. This will cause the famous The Diamond Problem. The solution is simply to override the default method with its own implementation.
static methods in Interface
Interfaces from Java 8 onwards can have static methods with implementation. But unlike default methods, these methods can’t be overridden by the classes implementing the interface containing static methods.
Java Stream API
Stream API is used to process collections of objects. It uses streams that can perform aggregate operations on data returned from collections and I/O operations. Stream operations are either intermediate (it returns the stream itself for further operations) or terminal (it returns the result of a specific type). Streams incorporate something called Parallel execution of Operations which drastically improves the performance of the code.
To explain the Parallel execution of Operations, let me illustrate it with an example.
As shown in the two examples, counting collection using traditional methods iterates through the list, checks the condition and then outputs the result. When counting the collection using streams, the stream() method returns a stream of all the names, the filter() method returns another stream of names with length more than 5, the count() method reduces this stream to the result. All these operations occur parallelly. This comes in handy when there are thousands of records in the collection, streams will output the result in lesser time thereby increasing the performance.
Prior to Java 8 release, developers had to write null checks in order to avoid NullPointerException which can crash the application. Java 8 has introduced a new class Optional which can help in writing a clean code without using too many null checks. By using Optional, we can specify alternate values to return or alternate code to run.
My Final Thoughts
These are some of the most important features that we are using since the release of Java 8. These features have highly improved the performance, eased off the development tasks and made Java more efficient. With more releases coming in several months, it is important to know the new features to maximize Java to its potential. Java is and will always be one of the most important programming languages despite facing stiff competition from Python.