Java 8 Important Features

Deepika sharma
Javarevisited
Published in
4 min readNov 20, 2020

Java 8 was released on March 18, 2014. It was a revolutionary release for the software development platform with various enhancements made to Java programming, JVM, Tools, and libraries. Following are few of the important and useful Java 8 Features:

Functional Interfaces :

A functional interface is a new concept introduced in Java 8. Interface with exactly one abstract method becomes Functional Interface, however, it can have any number of default or static methods,It can also declare methods of an Object class(ex: toString()).

We don’t need to use @functionalInterface annotation to mark an interface as Functional Interface but this annotation is a facility to avoid accidental addition of abstract methods in the functional interfaces. java.lang.Runnable with single abstract method run() is a great example of functional interface. Lambda expressions can be used to represent the instance of a functional interface

1. Lambda Expressions:

Lambda expressions provide a precise way to implement the Single Abstract Method (Functional Interface) by using an expression. Since functional interfaces have only one method, lambda expressions can easily provide the method implementation where we just need to provide method arguments and business logic. It is also very useful in the collection library in which it helps to iterate, filter and extract data.

For Instance, take the below code for implementing the runnable interface

Runnable r = new Runnable(){
@Override
public void run() {
System.out.println(“My Runnable”);
}};

with Lambda expressions, above code can be shorten to just single line :

Runnable r1 = () -> { System.out.println(“My Runnable”); };

Lambda expressions are treated as a function so the compiler does not create a .class file separately.

2. Method References

Method reference helps us to point methods by their names. It is described using:: symbol and can be used with static or instance methods and also with constructor using new operator like TreeSet::new. Method reference is a shorthand notation of a lambda expression to call a method.

str -> System.out.println(str)

you can replace the above lambda expression with a method reference like System.out::println .

Example :

public class Abc {
public static void thrd(){
System.out.println(“Thread is running !”);
}
public static void main(String[] args) {
Thread t2=new Thread(Abc::thrd);
t2.start(); }}

3. forEach:

Java 8 provides a new method forEach() to iterate over Collections and Streams. It is defined in Iterable and Stream interfaces.
Whenever we need to traverse through a Collection, we need to create an Iterator and in the process of it, we might get ConcurrentModificationException if the iterator is not used properly.

Collection classes that extend the Iterable interface can use the forEach() method to iterate elements. This method takes a single parameter which is a functional interface. So, we can pass a lambda expression as an argument.
For Example:

public static void main(String[] args) {
List<String> list= new ArrayList<String>();
list.add(“Apple”);
list.add(“Orange”);
list.add(“Banana”);
//lambda expression in forEach Method
list.forEach(str->System.out.println(str));
//above line can also be written using method reference as
list.forEach(System.out::println));
}

4. Stream API

Stream is an abstract layer introduced in Java 8. With Streams , we can process data in a declarative way just like Sql statements. It represents a sequence of objects from a source which supports aggregate functions. Stream API will allow sequential as well as parallel execution.

Collection interface has been extended with stream() and parallelStream() default methods to get the Stream for sequential and parallel execution. We can use a stream to filter, collect, print, and convert from one data structure to another, etc.

Stream is functional in nature. Operations performed on a stream does not modify it’s source. For example, filtering a Stream obtained from a collection produces a new Stream without the filtered elements, rather than removing elements from the source collection.

Stream operations do the iterations internally over the source element, in contrast to collections where explicit iteration is required.
Example for Stream filter :

 public static void main(String[] args) { 
List<Product> products = new ArrayList<Product>();
//Adding Products
products.add(new Product(1,”Fruits”,20000f));
products.add(new Product(2,”Vehicle”,33000f));
products.add(new Product(3,”Household”,25000f));

List<Float> priceList =products.stream()
.filter(p -> p.price > 30000) // filtering data
.map(p->p.price) // fetching price
.collect(Collectors.toList()); // collecting as list
System.out.println(priceList); // will print [33000.0]
}

you can check this for more examples and all the methods supported by Java 8 Stream API.

5. Default and Static Methods in Interfaces
Java 8 allows the interfaces to have default and static methods. Reason for having default methods in interfaces is to allow the developers to add new methods to the interfaces without affecting the classes that implements these interfaces which makes it backward compatible.

Backward compatibility is adding new features without breaking the old code.

Static methods in interfaces are similar to the default methods except that we cannot override these methods in the classes that implement these interfaces.

interface ParentInt{  
default void defaultMet(){
System.out.println("default method");
}
static void staticMet(){
System.out.println("static method");
}
void existingMet(String str);
}
public class child implements ParentInt{

public void existingMet(String str){
System.out.println("String is: "+str);
}
public static void main(String[] args) {
Example obj = new Example();

//calling the default method of interface
obj.defaultMet();
//calling the static method of interface
ParentInt.staticMet();
//calling the abstract method of interface
obj.existingMet("Java 8 Features ");
}
}

Output :

default method
static method
String is: Java 8 Features

6. Base64 Encoding and Decoding :

One more feature introduced in Java 8 is Base64 Encoding and Decoding. It provides a class Base64 to deal with encryption and decryption. We need to import java.util.Base64 class in our source file to use its methods.
Prior to Java 8 for we needed to add external jars like Apache Commons Codec’s Base64.encodeBase64(byte[]) and Base64.decodeBase64(byte[])as shown here, or Sun’s internal base64 encoder and decoder, sun.misc.BASE64Encoder().encode() and sun.misc.BASE64Decoder().decode()

That’s all about some of the important features introduced in Java 8. Hope you find it useful.

Thanks !! :)

--

--