Java 8 Features

Java 8 was a significant release that introduced many new features to the Java programming language. These features were designed to make Java more powerful and expressive, allowing developers to write cleaner and more efficient code. In this guide, we will cover all the major features introduced in Java 8.

Check out 100+ Java 8 tutorials, programs, examples, and guides: Java 8 Tutorial.

Key Features in Java 8

  1. Lambda Expressions
  2. Functional Interfaces
  3. Streams API
  4. Optional Class
  5. Default and Static Methods in Interfaces
  6. New Date and Time API
  7. Nashorn JavaScript Engine
  8. Parallel Array Sorting
  9. Type Annotations
  10. Method References
  11. Collectors
  12. New Files API (NIO.2)

Let's explore each feature in detail with examples.

1. Lambda Expressions

What are Lambda Expressions?

Lambda expressions provide a clear and concise way to represent one method interface using an expression. They are used primarily to define the implementation of a functional interface.

Syntax

(parameters) -> expression

(parameters) -> { statements; }

Example

import java.util.Arrays;
import java.util.List;

public class LambdaExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Ramesh", "Suresh", "Kamlesh", "Priya");

        // Using a lambda expression to iterate through the list
        names.forEach(name -> System.out.println(name));
    }
}

Output:

Ramesh
Suresh
Kamlesh
Priya

Explanation

  • names.forEach(name -> System.out.println(name)); uses a lambda expression to print each name in the list.

Learn more at the link: Java 8 Lambda Expressions.

2. Functional Interfaces

What are Functional Interfaces?

A functional interface is an interface that has exactly one abstract method. Java 8 introduced the @FunctionalInterface annotation to define a functional interface. Lambda expressions can be used to instantiate functional interfaces.

Example

@FunctionalInterface
interface GreetingService {
    void sayMessage(String message);
}

public class FunctionalInterfaceExample {
    public static void main(String[] args) {
        // Lambda expression implementing the sayMessage method
        GreetingService greet = message -> System.out.println("Hello, " + message);
        greet.sayMessage("Ramesh");
    }
}

Output:

Hello, Ramesh

Explanation

  • The GreetingService interface has one abstract method, sayMessage, making it a functional interface.
  • The lambda expression message -> System.out.println("Hello, " + message) provides an implementation for the sayMessage method.

Learn more at the link: Java 8 Functional Interfaces.

3. Streams API

What is the Streams API?

The Streams API is a new abstraction introduced in Java 8 that allows you to process sequences of elements (such as collections) in a functional style. Streams support operations like mapping, filtering, and reduction.

Example

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamsExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Filtering even numbers and collecting them into a list
        List<Integer> evenNumbers = numbers.stream()
                                           .filter(n -> n % 2 == 0)
                                           .collect(Collectors.toList());

        System.out.println("Even Numbers: " + evenNumbers);
    }
}

Output:

Even Numbers: [2, 4, 6, 8, 10]

Explanation

  • numbers.stream() creates a stream from the list of numbers.
  • .filter(n -> n % 2 == 0) filters out only even numbers.
  • .collect(Collectors.toList()) collects the filtered elements into a new list.

Learn more at the link: Java 8 Stream API.

4. Optional Class

What is the Optional Class?

The Optional class is a container object which may or may not contain a non-null value. It is used to avoid null checks and NullPointerExceptions.

Example

import java.util.Optional;

public class OptionalExample {
    public static void main(String[] args) {
        Optional<String> optionalName = Optional.of("Ramesh");

        // Check if the optional contains a value
        if (optionalName.isPresent()) {
            System.out.println("Name: " + optionalName.get());
        } else {
            System.out.println("Name not found");
        }

        // Using ifPresent to execute a lambda expression if a value is present
        optionalName.ifPresent(name -> System.out.println("Hello, " + name));
    }
}

Output:

Name: Ramesh
Hello, Ramesh

Explanation

  • Optional.of("Ramesh") creates an Optional containing the string "Ramesh".
  • optionalName.isPresent() checks if the Optional contains a value.
  • optionalName.ifPresent(name -> System.out.println("Hello, " + name)) executes the lambda expression if a value is present.

Learn more at the link: Java 8 Optional Class.

5. Default and Static Methods in Interfaces

What are Default and Static Methods?

Java 8 introduced default and static methods in interfaces, allowing developers to add new methods to interfaces without breaking existing implementations.

Example

interface Vehicle {
    // Default method
    default void print() {
        System.out.println("I am a vehicle");
    }

    // Static method
    static void blowHorn() {
        System.out.println("Blowing horn");
    }
}

public class DefaultMethodExample implements Vehicle {
    public static void main(String[] args) {
        DefaultMethodExample car = new DefaultMethodExample();
        car.print();          // Calls the default method in the interface
        Vehicle.blowHorn();   // Calls the static method in the interface
    }
}

Output:

I am a vehicle
Blowing horn

Explanation

  • print() is a default method in the Vehicle interface.
  • blowHorn() is a static method in the Vehicle interface, which can be called using the interface name.

Learn more at the link: Java 8 Static and Default Methods in Interface.

6. New Date and Time API

What is the New Date and Time API?

Java 8 introduced a new date and time API under the java.time package, providing a more comprehensive and robust date and time handling compared to the previous java.util.Date and java.util.Calendar classes.

Example

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;

public class DateTimeExample {
    public static void main(String[] args) {
        // Current date
        LocalDate date = LocalDate.now();
        System.out.println("Current Date: " + date);

        // Current time
        LocalTime time = LocalTime.now();
        System.out.println("Current Time: " + time);

        // Current date and time
        LocalDateTime dateTime = LocalDateTime.now();
        System.out.println("Current Date and Time: " + dateTime);

        // Specific date
        LocalDate specificDate = LocalDate.of(2023, 8, 10);
        System.out.println("Specific Date: " + specificDate);
    }
}

Output:

Current Date: 2023-08-07
Current Time: 12:34:56.789
Current Date and Time: 2023-08-07T12:34:56.789
Specific Date: 2023-08-10

Explanation

  • LocalDate, LocalTime, and LocalDateTime are part of the new date and time API.
  • LocalDate.now() gets the current date.
  • LocalTime.now() gets the current time.
  • LocalDateTime.now() gets the current date and time.
  • LocalDate.of(2023, 8, 10) creates a specific date.
Learn more at the linkJava 8 Date Time API Tutorial

7. Nashorn JavaScript Engine

What is the Nashorn JavaScript Engine?

The Nashorn JavaScript engine, introduced in Java 8, allows developers to execute JavaScript code within Java applications.

Example

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class NashornExample {
    public static void main(String[] args) {
        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");

        String script = "var name = 'Ramesh'; name;";
        try {
            Object result

 = nashorn.eval(script);
            System.out.println("Result: " + result);
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }
}

Output:

Result: Ramesh

Explanation

  • ScriptEngineManager is used to get a ScriptEngine for executing JavaScript.
  • nashorn.eval(script) executes the JavaScript code and returns the result.

8. Parallel Array Sorting

What is Parallel Array Sorting?

Java 8 introduced the ability to sort arrays in parallel using multiple threads, improving performance for large arrays.

Example

import java.util.Arrays;

public class ParallelSortExample {
    public static void main(String[] args) {
        int[] numbers = {5, 3, 8, 1, 9, 4, 7, 6, 2, 0};

        System.out.println("Before Sorting: " + Arrays.toString(numbers));
        
        // Parallel sort
        Arrays.parallelSort(numbers);

        System.out.println("After Sorting: " + Arrays.toString(numbers));
    }
}

Output:

Before Sorting: [5, 3, 8, 1, 9, 4, 7, 6, 2, 0]
After Sorting: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Explanation

  • Arrays.parallelSort(numbers) sorts the array in parallel using multiple threads.

9. Type Annotations

What are Type Annotations?

Java 8 introduced the ability to annotate types, providing more granular control over annotations. These can be used with any type, including generics and casts.

Example

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.TYPE_USE)
@interface NonNull {}

public class TypeAnnotationExample {
    public static void main(String[] args) {
        @NonNull String name = "Ramesh";
        System.out.println("Name: " + name);
    }
}

Output:

Name: Ramesh

Explanation

  • @Target(ElementType.TYPE_USE) specifies that the annotation can be used on any type use.
  • @NonNull String name demonstrates the use of a type annotation.

10. Method References

What are Method References?

Method references provide a shorthand syntax for calling a method directly from a lambda expression. They make code more readable by eliminating unnecessary code.

Example

import java.util.Arrays;
import java.util.List;

public class MethodReferenceExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Ramesh", "Suresh", "Kamlesh");

        // Using method reference to print each name
        names.forEach(System.out::println);
    }
}

Output:

Ramesh
Suresh
Kamlesh

Explanation

  • System.out::println is a method reference that refers to the println method of the System.out object.

Learn more at the link: Java 8 Method References.

11. Collectors

What are Collectors?

Collectors are used in conjunction with the Streams API to accumulate elements into collections or other summary results.

Example

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CollectorsExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Ramesh", "Suresh", "Ramesh", "Priya");

        // Grouping names by their length
        Map<Integer, List<String>> groupedNames = names.stream()
                                                      .collect(Collectors.groupingBy(String::length));

        System.out.println("Grouped Names: " + groupedNames);
    }
}

Output:

Grouped Names: {5=[Ramesh, Suresh, Ramesh], 5=[Priya]}

Explanation

  • Collectors.groupingBy(String::length) groups the names based on their length.

Learn more at the link: Java 8 Collectors Class.

12. New Files API (NIO.2)

What is the New Files API?

Java 8 introduced enhancements to the java.nio.file package, providing more robust file handling capabilities, such as directory stream handling, file reading, writing, and file system access.

Example

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

public class FilesExample {
    public static void main(String[] args) {
        String filePath = "example.txt";
        
        try {
            // Writing to a file
            Files.write(Paths.get(filePath), "Hello, Ramesh!".getBytes());

            // Reading from a file
            List<String> lines = Files.readAllLines(Paths.get(filePath));
            lines.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Output:

Hello, Ramesh!

Explanation

  • Files.write(Paths.get(filePath), "Hello, Ramesh!".getBytes()) writes the text to a file.
  • Files.readAllLines(Paths.get(filePath)) reads all lines from the file into a list.

Conclusion

In this guide, we explored briefly the key features introduced in Java 8. Java 8 brought many improvements to the Java programming language, including lambda expressions, streams, the new date and time API, and more. These features enable developers to write more efficient, readable, and maintainable code. By understanding and utilizing these features, you can take full advantage of Java 8 in your applications.

Check out 100+ Java 8 tutorials, programs, examples, and guides: Java 8 Tutorial.

Series: Java Release-wise New Features

Comments