Resolving default-method conflicts, why default methods exist and the problem they solve, static vs default interface methods, how Java 8 stayed backward-compatible, and Optional done right — of vs ofNullable, handling absence, and why not to use it as a parameter.
Published September 25, 2026
Default methods and Optional are both API-design tools. Interviewers want to see that you know the mechanics, and the idioms. Optional in particular is often misused: get() without a check, Optional fields, Optional parameters. Show the right style.
Short answer: The compiler forces the class to override the conflicting method. Inside the override, you can delegate to a specific interface's version with InterfaceName.super.method(), or combine them.
interface Auditable { default String describe() { return "auditable"; } }
interface Exportable { default String describe() { return "exportable"; } }
class Invoice implements Auditable, Exportable {
@Override public String describe() {
return Auditable.super.describe() + "+" + Exportable.super.describe(); // explicit choice
}
}
Key points to cover:
B extends A, and both define the method, B's version is used.Learn it in depth → Interfaces and Abstract Classes
Short answer: A default method is an interface method with a body (default keyword), which implementing classes inherit and may override. It was introduced so interfaces could evolve: the JDK needed to add stream(), forEach() and removeIf() to Collection and Iterable without breaking the millions of existing classes that implement them.
Short answer:
default method | static method | |
|---|---|---|
| Called on | An instance (list.forEach(...)) | The interface (Comparator.naturalOrder()) |
| Inherited by implementations | Yes | No: not even callable as Impl.method() |
| Overridable | Yes | No |
| Typical use | Behaviour that evolves the contract | Factories and utilities related to the interface |
public interface Discount {
BigDecimal apply(BigDecimal price);
default Discount then(Discount next) { return p -> next.apply(apply(p)); } // instance behaviour
static Discount percent(int pct) { // factory
return p -> p.multiply(BigDecimal.valueOf(100 - pct)).divide(BigDecimal.valueOf(100));
}
}
Key points to cover:
Collection / Collections style).private interface methods, for helper code shared between default methods.Short answer: In three ways:
Runnable and Comparator worked immediately), and default methods let the core interfaces gain methods without forcing any implementation to change.Key points to cover:
Short answer: The interface evolution problem. Before Java 8, adding a method to a published interface broke every implementing class, both in source and at runtime (AbstractMethodError). Library authors were stuck: either freeze the interface forever, or ship a parallel Interface2. Default methods let an interface add behaviour with a sensible default, while implementations stay compatible, and can override it when they have something better.
Key points to cover:
Comparator.reversed, Predicate.and). But interfaces still have no instance state, so they don't replace abstract classes.Optional, and how is it used?Short answer: Optional<T> is a container that is either empty, or holds a non-null value. It makes "there may be no result" explicit in a method's return type, and it offers functional methods for handling both cases, instead of scattered null checks.
Optional<Customer> customer = customerRepository.findByEmail(email); // Spring Data returns Optional
String city = customer.map(Customer::address)
.map(Address::city)
.orElse("Unknown");
Customer c = customer.orElseThrow(() -> new CustomerNotFoundException(email));
customer.ifPresentOrElse(this::sendWelcomeBack, this::sendSignupInvite);
Key points to cover:
Serializable, and it adds an allocation, so it isn't meant for fields, parameters or collections.orElseGet(() -> expensive()) to orElse(expensive()). The argument to orElse is always evaluated, even when a value is present.Learn it in depth → Optional
Optional?Short answer: Wrap the possibly-null value with Optional.ofNullable(value), then transform it and supply defaults without explicit checks:
String displayName = Optional.ofNullable(user.nickname()) // may be null
.filter(n -> !n.isBlank())
.or(() -> Optional.ofNullable(user.fullName())) // Java 9: a fallback Optional
.orElse("Guest");
Common trap: if (opt.isPresent()) { return opt.get(); }. That's just a verbose null check. Use map, orElse, orElseThrow or ifPresent. And never return null from a method whose return type is Optional.
Optional.of() and Optional.ofNullable()?Short answer: Optional.of(value) requires a non-null value. It throws NullPointerException immediately if the value is null, which is useful as an assertion. Optional.ofNullable(value) accepts null, and returns Optional.empty() for it.
Key points to cover:
of when a null would be a bug (fail fast), and ofNullable when the value comes from an API that may legitimately return null.Optional as a method parameter?Short answer: Generally no:
search(Optional.empty())).null for the Optional itself.Optional was designed as a return type.
// ❌ callers must wrap: find(Optional.of("Pune"))
List<Store> find(Optional<String> city);
// ✅ clearer alternatives
List<Store> findAll();
List<Store> findByCity(String city);
List<Store> find(StoreFilter filter); // a filter object with nullable fields
Key points to cover:
Optional.ofNullable(field) from the getter if that helps callers.Q: What did Java 9–11 add to Optional?
A: ifPresentOrElse, or and stream() in Java 9, orElseThrow() with no arguments in Java 10 (a clearer name than get()), and isEmpty() in Java 11.
Q: How do you turn a stream of Optionals into the present values?
A: optionals.stream().flatMap(Optional::stream).toList() (Java 9+).
Q: Why is Optional.get() discouraged?
A: It throws NoSuchElementException when the Optional is empty, so it merely replaces an NPE with another exception. Use orElseThrow() to make the intent explicit, or one of the functional methods.
Q: Can a default method override a method from Object, such as toString?
A: No. Declaring default String toString() in an interface is a compile error. Class methods always win, so such a default would never be used.