Modern Java: Lambdas, Optional, Records and Sealed Classes
Codevity Admin · 10/25/2026
Step 19 of 38 · Java Interview Preparation for Beginners · Stage 4: Modern Java and streams
Codevity Admin · 10/25/2026
Interviewers increasingly ask about features added since Java 8. This article covers the ones that come up most, in the order they arrived: lambdas (Java 8), Optional (Java 8), records (Java 16), sealed classes (Java 17), and switch expressions and pattern matching (Java 14 to 21).
A functional interface has exactly one abstract method. @FunctionalInterface is optional, but it makes the compiler reject a second abstract method. A lambda is a short way to implement one:
import java.util.*;
import java.util.function.*;
public class Lambdas {
public static void main(String[] args) {
Function<Integer, Integer> square = x -> x * x;
Predicate<String> isLong = s -> s.length() > 4;
Supplier<String> greeting = () -> "hello";
Consumer<String> printer = s -> System.out.println("LOG: " + s);
BiFunction<Integer, Integer, Integer> add = Integer::sum;
System.out.println(square.apply(5)); // 25
System.out.println(isLong.test("banana")); // true
System.out.println(greeting.get()); // hello
printer.accept("started"); // LOG: started
System.out.println(add.apply(2, 3)); // 5
List<String> names = new ArrayList<>(List.of("Ben", "asha", "Carla"));
names.sort(String::compareToIgnoreCase); // a method reference
System.out.println(names); // [asha, Ben, Carla]
int base = 10; // a captured local variable must be effectively final
Function<Integer, Integer> addBase = n -> n + base;
System.out.println(addBase.apply(5)); // 15
}
}| Interface | Method | Meaning |
|---|---|---|
Function<T, R> | R apply(T) | Transform a value |
Predicate<T> | boolean test(T) | Test a condition |
Consumer<T> | void accept(T) | Use a value, return nothing |
Supplier<T> | T get() | Produce a value |
Runnable / Callable<V> | run() / call() | A task. Callable returns a value and may throw |
Comparator<T> | int compare(T, T) | Define an order |
Method references are shorthand for a lambda that only calls a method: String::length (instance method of any object), System.out::println (instance method of a given object), Integer::parseInt (static method) and ArrayList::new (constructor).
public class Functional {
@FunctionalInterface
interface Validator {
boolean validate(String input); // exactly one abstract method
}
public static void main(String[] args) {
Validator notBlank = s -> !s.isBlank();
System.out.println(notBlank.validate(" ")); // false
Validator legacy = new Validator() { // the anonymous class equivalent
@Override
public boolean validate(String input) { return !input.isBlank(); }
};
System.out.println(legacy.validate("x")); // true
}
}| Lambda | Anonymous inner class | |
|---|---|---|
| Works with | Functional interfaces only | Any interface or class |
this | The enclosing object | The anonymous object itself |
| Compiled as | An invokedynamic call (no extra .class file) | A separate class file |
| Syntax | Short | Verbose |
Optional<T> is a container that may or may not hold a value. Its purpose is to make "there might be no result" visible in a method's return type, instead of returning null.
import java.util.*;
public class OptionalDemo {
public static void main(String[] args) {
System.out.println(findUser("asha").map(String::toUpperCase).orElse("unknown")); // ASHA
System.out.println(findUser("zed").map(String::toUpperCase).orElse("unknown")); // unknown
findUser("zed").ifPresentOrElse(
user -> System.out.println("found " + user),
() -> System.out.println("nobody")); // nobody
try {
findUser("zed").orElseThrow(() -> new NoSuchElementException("no user zed"));
} catch (NoSuchElementException e) {
System.out.println(e.getMessage()); // no user zed
}
}
static Optional<String> findUser(String name) {
return name.equals("asha") ? Optional.of("asha") : Optional.empty();
}
}Use it as a return type. Do not use it for:
Serializable, and it adds overhead),Prefer , , , and over followed by , which is just a verbose null check.
A record is a transparent, immutable data carrier. The compiler generates the constructor, the accessors (, not ), , and .
A record's fields are , it cannot extend another class (it implicitly extends ) and it cannot be extended, but it can implement interfaces and have methods and static members. Use records for DTOs, map keys, return values and messages.
A sealed type lists exactly which classes may extend it, and each permitted subclass must be , or . With pattern matching for (final in Java 21), the compiler knows every possible subtype, so a over a sealed type needs no , and adding a new subtype turns a forgotten case into a compile error:
| Java | Feature |
|---|---|
| 8 | Lambdas, streams, , default and static interface methods, |
| 9 | Modules, , private interface methods |
| 10 | for local variables |
| 14 | Switch expressions ( and ) |
| 15 | Text blocks () |
| 16 | Records, pattern matching for () |
| 17 | Sealed classes |
| 21 | Virtual threads, pattern matching for , record patterns |
maporElseorElseGetorElseThrowifPresentisPresent()get()x()getX()equalshashCodetoStringfinaljava.lang.Recordfinalsealednon-sealedswitchswitchdefaultOptionaljava.timeList.ofvar->yield"""instanceofif (o instanceof String s)switchComparatorfinalequalshashCodepublic class Records {
public static void main(String[] args) {
Range range = new Range(1, 5);
System.out.println(range); // Range[low=1, high=5]
System.out.println(range.equals(new Range(1, 5))); // true
System.out.println(range.length()); // 4
try {
new Range(5, 1);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage()); // low must not exceed high
}
}
}
record Range(int low, int high) {
Range { // compact constructor: validate here
if (low > high) throw new IllegalArgumentException("low must not exceed high");
}
int length() { return high - low; }
}public class Shapes {
public static void main(String[] args) {
System.out.println(area(new Circle(1))); // 3.141592653589793
System.out.println(area(new Rect(2, 3))); // 6.0
System.out.println(describe(42)); // integer 42
System.out.println(describe("hi")); // text of length 2
System.out.println(describe(null)); // nothing
}
static double area(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rect r -> r.width() * r.height(); // exhaustive: no default needed
};
}
static String describe(Object value) {
return switch (value) {
case null -> "nothing";
case Integer i -> "integer " + i;
case String s -> "text of length " + s.length();
default -> "something else";
};
}
}
sealed interface Shape permits Circle, Rect {}
record Circle(double radius) implements Shape {}
record Rect(double width, double height) implements Shape {}