Skip to content

Java 8 Features

Java 8, released in March 2014, introduced several new features and enhancements to the Java programming language, making it more powerful, modern, and functional. The most notable changes in Java 8 were the introduction of Lambda Expressions, the Stream API, new Date and Time API, and other language and library improvements.

Here’s a breakdown of the major features introduced in Java 8:


1. Lambda Expressions

Lambda expressions provide a clear and concise way to represent an instance of a functional interface. They enable you to treat functionality as a method argument or to create a short implementation for a method in a functional style.

Syntax:

java
(parameters) -> expression

Lambda expressions are especially useful for passing behavior as a parameter to methods, such as when using the Stream API or functional interfaces.

Example:

java
// Without Lambda
Thread t1 = new Thread(new Runnable() {
    public void run() {
        System.out.println("Hello, world!");
    }
});

// With Lambda
Thread t2 = new Thread(() -> System.out.println("Hello, world!"));
t2.start();

Explanation:

  • Runnable interface is a functional interface with a single abstract method run().
  • The lambda expression () -> System.out.println("Hello, world!") replaces the anonymous inner class.

2. Functional Interfaces

A functional interface is an interface with just one abstract method. Java 8 introduced a set of predefined functional interfaces in the java.util.function package, such as Function, Predicate, Consumer, Supplier, etc.

  • Functional Interface Example:

    java
    @FunctionalInterface
    public interface MyFunctionalInterface {
        void myMethod();  // One abstract method
    }
  • Java 8 also introduced the @FunctionalInterface annotation to ensure that the interface contains exactly one abstract method.


3. Stream API

The Stream API was introduced in Java 8 to process sequences of elements (such as collections) in a functional style. A stream is a sequence of data elements that can be processed in parallel or sequentially.

Streams allow operations like filtering, mapping, and reducing on collections of data.

Example:

java
import java.util.*;
import java.util.stream.*;

public class StreamExample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");

        // Using Stream to filter and print
        list.stream()
            .filter(s -> s.startsWith("b"))
            .forEach(System.out::println);  // Output: banana
    }
}

Key Stream Operations:

  • Filter: Removes elements based on a condition.
  • Map: Transforms each element.
  • Reduce: Combines elements into a single result (e.g., sum, product).
  • Collect: Collects the results into a different data structure.

Example of Mapping and Reducing:

java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
                 .mapToInt(Integer::intValue)  // Converts to int
                 .sum();  // Reduce to a sum

System.out.println("Sum: " + sum);  // Output: 15

4. Default Methods in Interfaces

Java 8 introduced default methods in interfaces. This allows interfaces to have method implementations. Default methods are used to add new functionality to interfaces without breaking existing implementations.

Syntax:

java
interface MyInterface {
    default void sayHello() {
        System.out.println("Hello from default method!");
    }
}

This allows interfaces to evolve without breaking existing classes that implement those interfaces.

Example:

java
interface MyInterface {
    default void greet() {
        System.out.println("Hello, Java 8!");
    }
}

public class MyClass implements MyInterface {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        obj.greet();  // Calls default method
    }
}

5. New Date and Time API (java.time)

The java.time package introduced in Java 8 provides a modern and comprehensive API for handling dates and times. It replaces the older java.util.Date and java.util.Calendar classes, which were cumbersome and error-prone.

The key classes in the new API are:

  • LocalDate: Represents a date (year, month, day).
  • LocalTime: Represents a time without a date (hour, minute, second).
  • LocalDateTime: Combines date and time.
  • ZonedDateTime: Represents a date and time with a time zone.
  • Duration and Period: Represent time-based amounts (e.g., hours, days).

Example:

java
import java.time.*;

public class DateTimeExample {
    public static void main(String[] args) {
        LocalDate date = LocalDate.now();  // Get current date
        LocalTime time = LocalTime.now();  // Get current time
        LocalDateTime dateTime = LocalDateTime.now();  // Get current date and time

        System.out.println("Current Date: " + date);
        System.out.println("Current Time: " + time);
        System.out.println("Current DateTime: " + dateTime);
    }
}

Key Methods:

  • now(): Gets the current date, time, or date-time.
  • plusDays(), minusMonths(): Adds or subtracts time from a date/time.
  • format(): Formats the date/time into a string.

6. Method References

Method references are a shorthand for calling a method using a lambda expression. They allow methods to be passed as arguments to other methods.

Syntax:

java
ClassName::methodName

Types of Method References:

  1. Static method reference: ClassName::staticMethod
  2. Instance method reference: instance::instanceMethod
  3. Constructor reference: ClassName::new

Example:

java
import java.util.*;
import java.util.function.*;

public class MethodReferenceExample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("apple", "banana", "cherry");

        // Using method reference for print
        list.forEach(System.out::println);
    }
}

Example: Constructor Reference

java
interface MyFactory {
    MyClass create(String name);
}

class MyClass {
    private String name;

    public MyClass(String name) {
        this.name = name;
    }

    public void greet() {
        System.out.println("Hello, " + name);
    }
}

public class ConstructorReferenceExample {
    public static void main(String[] args) {
        MyFactory factory = MyClass::new;  // Constructor reference
        MyClass obj = factory.create("John");
        obj.greet();  // Output: Hello, John
    }
}

7. Optional Class

The Optional class is a container object used to prevent NullPointerException by representing an optional value that may or may not be present.

Usage:

  • Optional.of(): Creates an Optional with a non-null value.
  • Optional.empty(): Creates an empty Optional.
  • Optional.ifPresent(): Executes a block of code if the value is present.
  • Optional.orElse(): Provides a default value if the value is absent.

Example:

java
import java.util.Optional;

public class OptionalExample {
    public static void main(String[] args) {
        Optional<String> optional = Optional.ofNullable(null);
        
        // If present, print the value, otherwise print "Value not present"
        optional.ifPresentOrElse(
            System.out::println, 
            () -> System.out.println("Value not present")
        );
    }
}

8. Parallel Streams

Java 8 introduces parallel streams, which allow you to perform stream operations in parallel, taking advantage of multi-core processors for better performance.

Example:

java
import java.util.*;
import java.util.stream.*;

public class ParallelStreamExample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        // Using parallel stream to compute sum
        int sum = list.parallelStream()
                      .mapToInt(Integer::intValue)
                      .sum();
        
        System.out.println("Sum: " + sum);
    }
}

Conclusion

Java 8 brought significant advancements to the Java language, particularly in functional programming and handling of dates and times. The key features are:

  • Lambda Expressions: Introduced functional programming style to Java.
  • Stream API: Enables functional-style operations on sequences of data.
  • Default Methods: Allow adding new methods to interfaces without breaking existing implementations.
  • New Date and Time API: A comprehensive and immutable API for working with dates and times.
  • Method References: Provide a concise way to invoke methods via lambdas.
  • Optional Class: Helps avoid NullPointerException by handling the absence of values.
  • Parallel Streams: Allows easy parallelization of stream processing.

Java 8 revolutionized how Java developers write code by making it more expressive, efficient, and functional.

J2J Institute private limited