In this article we are going to discuss the most important features of Java 8. I would be discussing these features with examples.
Functional Interfaces
Functional interfaces are interfaces with exactly one method. They can have an annotation with @FunctionalInterface
. A very good example of Function Interface is that of the Comparable
. It has exactly one method compareTo(obj)
. Functional Interfaces are used extensively used with lamda expressions.
Lambda Expressions
Lambda expression is considered to be one of the most important features of Java 8. Lamda expressions have the following syntax
parameter->body
Lambda expressions don’t need the parameters to be declared with type as that can be inferred by compiler from the value of parameter. For single parameter no parenthesis are needed. For single expression body statement no curly braces are needed. Single expression doesn’t need a return.
Lambda expressions are mostly used to create the anonymous classes of functional interfaces without declaring the class and all the boilerplate code. Here is an example that sorts a list of Person
objects on firstName
.
Collections.sort(list, (person1, person2) -> person1.getFirstName().compareTo(person2.getFirstName()));
Default and static methods in interfaces
Java 8 bought a major change in inheritances from interfaces. Till Java 7, interfaces only had methods signatures and no implementation of a a method was allowed. But in Java 8, it changed and now interfaces can have a method implementation. By defining a method as default, and providing an implementation the method no longer needs to be implemented by all the implementing classes. If any class in the hierarchy has a method with same definition, then the method from class take over the functionality. That is why it is not allowed to provide a default method with same signature as any method from Object. The advantage of default methods is that the existing classes don’t need to implement this method and the existing code will compile without any changes. They even don’t need to be compiled e.g; if a jar file has a class compiled with old interface the jar doesn’t need to be created again.
In the following example, we have an existing Phone interface and we added a new feature to it. But the old phones that already are in the code base don’t need to implement this new feature. And someone invokes this new feature on an old Phone class, he would get the message.
public interface Phone { default void newFeature(){ System.out.println("Not found here! May be this is an old phone!"); } }
One thing to remember is that if a class implements two interfaces and both the interfaces have a default method with same signature, then class needs to implement this default method.
Static methods are similar to static methods in classes. Static methods are implemented in interfaces and cannot be overridden. Static methods belong to the interface.
I have written a detailed article on default and static methods. You can read it here
Iterable interface has forEach() method
This is not listed as a major feature anywhere in java 8 features. But this method is probably one of the most used methods of java 8. What this feature has done is that it has made iteration of collections more cleaner and more readable. You can a write a whole foreach in one liner if you are only having one statement in the loop. Let us look at the example below
package com.programtalk.learn.java.beginner; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; //programtalk.com public class Java8ForEach { public static void main(String[] args) { List<Integer> list =Arrays.asList(1,2,3,5,6); // normal loop for(Integer i : list){ System.out.println(i); } // same in Java 8 forEach Consumer<Integer> action = new IntegerConsumer(); list.forEach(action); // use lambda expressions, see how we do it in one liner list.forEach(each -> System.out.println(each)); } static class IntegerConsumer implements Consumer<Integer>{ @Override public void accept(Integer t) { System.out.println(t); } } }
As we saw above that we can have a consumer class that can have the business logic of handling each of the loop variables at a separate place that the loop itself. This can be helpful in making the code more clean.
java.util.stream
package provide new Stream API
Java collections got a new package java.util.Stream. The classes in this package provide a stream API. And supports functional-style operations on streams of elements. Stream API enables bulk operations like sequential or parallel map-readuce on Collections. Here is an example that does filtering on a large collection. In java 7 i would be doing something like below
List<Integer> filtered = new ArrayList<>(); for (Integer p : bigList) { if (p > 40) { filtered.add(p); } }
In java 8 with streams I can do it as below.
List<Integer> filtered = bigList.stream() . filter(p -> p > 40).collect(Collectors.toList());
You can see how easy and readable it is. So the stream applies some function on the data it contains and then returns the type of collection expected. So we don’t need to handle the intermediate results.
Java Date/Time API
Java Date/Time handling was long time due for a overhaul and in Java 8 the Java Time API tries to solve the problems developers have faced for a long time with handling date. It would be hard to talk about all the improvements but let me list some of them here
Date
/Time
API in java are immutable making usage in multithreaded code very safe. JavaDate
,SimpleDateFormatter
andCalender
classes are not Thread-safe due to being mutable.Date
/Time
API has classes that represent different use cases ofDate
andTime e.g.
LocalDate
– represents a date without timeLocalTime
– represents time without dateLocalDateTime -
represents a combination of date and timeZonedDateTime
– represents time zone specific date and timePeriod
– represents a qunatity of time in days, months, yearsDuration
-represents a quantity of time in nano seconds and seconds
- Date/Time API supports different calendaring systems.
Concurrency improvements
Some of the concurrency improvements are listed below:
- Important new classes in
java.util.concurrent
(CompletableFuture<T>, ConcurrentHashMap.KeySetView<K,V>, CountedCompleter<T>
) ConcurrentHashMap
class introduces over 30 new methods in this releasejava.util.concurrent.locks.StampedLock
has been added newly- scalable updatable variable support through a small set of new classes (
DoubleAccumulator
,DoubleAdder
,LongAccumulator
,LongAdder
)
Removal of PermGen
With Java 8 we have no more PermGen. So this configuration ‑XX:MaxPermSize is also gone. And if your moving from earlier version to java 8, you will get the warning about this property.
The metadata information is not contiguous to the java heap anymore and has moved to “Metaspace”.
Other important improvements
- Performance improvement for the
java.lang.String(byte[], *)
constructor and thejava.lang.String.getBytes()
method. - Parallel Array Sorting
- The JDBC-ODBC Bridge has been removed.
- JDK 8 includes Java Mission Control 5.3.
- JavaFx: The new Modena theme has been implemented in this release.