Java 8 was a revolutionary release that introduced functional programming concepts to Java. Subsequent versions (Java 9 through 21) have continued to add powerful features.
Lambda expressions introduced a new, concise syntax to write anonymous functions. They are used primarily to implement functional interfaces (interfaces with a single abstract method).
// Before Java 8 Runnable r1 = new Runnable() { @Override public void run() { System.out.println("Running..."); } };
// With Java 8 Lambda Runnable r2 = () -> System.out.println("Running...");
The Stream API is used to process collections of objects in a functional and declarative way. It supports filtering, mapping, and reducing.
List names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// Filter and print names starting with 'C' names.stream() .filter(name -> name.startsWith("C")) .forEach(System.out::println);
Optional is a container object used to contain not-null objects. It was introduced to avoid NullPointerException and provide a cleaner way to handle potentially null values.
Optional optional = Optional.ofNullable(getName());// Print if present, otherwise do nothing optional.ifPresent(System.out::println);
// Provide a default value if empty String name = optional.orElse("Default Name");
Interfaces can now have method implementations using the default keyword. This allowed the Java API to evolve without breaking existing code.
interface Vehicle { void start();// Default method default void honk() { System.out.println("Honk!"); }
}
Java 10 introduced var for local variables. The compiler infers the type based on the assigned value.
// Instead of: // List>> complexList = new ArrayList<>();
// Use var: var list = new ArrayList(); var message = "Hello"; // inferred as String
Switch expressions simplify switch statements, remove the need for break statements, and allow switch to return a value.
String day = "MONDAY";
int numLetters = switch (day) {
case "MONDAY", "FRIDAY", "SUNDAY" -> 6;
case "TUESDAY" -> 7;
case "THURSDAY", "SATURDAY" -> 8;
case "WEDNESDAY" -> 9;
default -> 0;
};
Records are a special kind of class that help to create immutable data carriers with minimal boilerplate. They automatically generate constructors, getters, equals(), hashCode(), and toString().
// A complete data class in one line! public record Point(int x, int y) {}
Point p = new Point(10, 20); System.out.println(p.x()); // 10