Definition
The evolution:
- Java 7: Only abstract methods and
static finalconstants. Every method must be implemented by the class. - Java 8: Added
defaultmethods (with a body) andstaticmethods. Enabled interface evolution without breaking existing implementations. - Java 9: Added
privatemethods for code reuse within default methods. - Java 17: Added
sealedinterfaces to control which classes can implement them.
Originally, a bank's service agreement (interface) only listed what services a branch must provide (abstract methods). In Java 8, the agreement started including pre-written standard procedures (default methods) that branches could use as-is or customize. In Java 9, the agreement allowed internal helper procedures (private methods). In Java 17, the agreement could specify exactly which branch types are allowed to sign it (sealed).
Understanding the Concepts
Java 7: abstract methods only
public interface AccountService {
BigDecimal getBalance(String accountId); // abstract (implicitly)
void transfer(String from, String to, BigDecimal amount); // abstract
}
// Every class MUST implement ALL methods
public class BasicAccountService implements AccountService {
@Override public BigDecimal getBalance(String id) { ... }
@Override public void transfer(String from, String to, BigDecimal amount) { ... }
}
Java 8: default and static methods
public interface AccountService {
BigDecimal getBalance(String accountId);
void transfer(String from, String to, BigDecimal amount);
// Default method: has a body, implementations inherit it
default boolean hasPositiveBalance(String accountId) {
return getBalance(accountId).signum() > 0;
}
// Static method: utility, called on the interface
static String formatAccountId(String raw) {
return raw.trim().toUpperCase();
}
}
// BasicAccountService gets hasPositiveBalance for free – no code change needed
String formatted = AccountService.formatAccountId(" sav2001 "); // "SAV2001"
Default methods solved the backward-compatibility problem: adding hasPositiveBalance to the interface does not break existing implementations.
Java 9: private methods
public interface AccountService {
default boolean isEligibleForLoan(String accountId) {
return hasMinBalance(accountId) && hasGoodHistory(accountId);
}
default boolean isEligibleForOverdraft(String accountId) {
return hasMinBalance(accountId); // reuses the private method
}
// Private: code reuse within the interface, not visible to implementors
private boolean hasMinBalance(String accountId) {
return getBalance(accountId).compareTo(new BigDecimal("10000")) >= 0;
}
private boolean hasGoodHistory(String accountId) {
return true; // simplified
}
BigDecimal getBalance(String accountId);
}
Private methods avoid duplicating code between default methods.
Java 17: sealed interfaces
public sealed interface Account permits SavingsAccount, CurrentAccount, LoanAccount {
BigDecimal getBalance();
}
// Only these three can implement Account
public final class SavingsAccount implements Account { ... }
public final class CurrentAccount implements Account { ... }
public final class LoanAccount implements Account { ... }
// public class FraudAccount implements Account { } // COMPILE ERROR: not permitted
Sealed interfaces enable exhaustive pattern matching in switch.
Summary table
| Feature | Java 7 | Java 8 | Java 9 | Java 17 |
|---|---|---|---|---|
| Abstract methods | Yes | Yes | Yes | Yes |
| Constants (static final) | Yes | Yes | Yes | Yes |
| default methods | No | Yes | Yes | Yes |
| static methods | No | Yes | Yes | Yes |
| private methods | No | No | Yes | Yes |
| sealed | No | No | No | Yes |
What should a senior engineer know?
- Diamond problem: If a class implements two interfaces with the same default method, it must override the method to resolve the conflict.
- Default methods do not break single responsibility. Use them for convenience methods that compose abstract methods, not for core logic.
- Spring uses default methods in repositories:
CrudRepositoryhas default save/findAll methods thatSimpleJpaRepositoryoverrides.
Visual Overview
Java 7: interface = abstract methods + constants only
Java 8: + default methods (body) + static methods
Java 9: + private methods (code reuse in defaults)
Java 17: + sealed (control who implements)
default method solves:
interface has 100 implementations
→ add new method with default body
→ all 100 implementations get it free, no changes needed
Key Takeaway
Interfaces evolved from abstract-method-only contracts (Java 7) to rich constructs with default methods, static methods, private methods, and sealed restrictions. Default methods solved backward compatibility: you can add new methods to an interface without breaking existing implementations. Private methods enable code reuse within default methods. Sealed interfaces control exactly which classes can implement them.
One sentence to remember: Java 8 added default and static methods, Java 9 added private methods, Java 17 added sealed – interfaces are now much more than just abstract method declarations.
---