When to use Java 8+ interface default method, vs. abstract method
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
In the realm of Java programming, the use of interfaces and abstract classes has evolved significantly, especially with the introduction of default methods in interfaces from Java 8 onwards. This feature has added more flexibility in design decisions and has slightly blurred the lines traditionally distinguishing interfaces from abstract classes. Understanding when to use a default method in an interface versus an abstract method in a class is crucial for designing robust, maintainable Java applications.
Default Methods in Interfaces
Prior to Java 8, interfaces could only contain method signatures without any implementation. But with Java 8, the concept of default methods was introduced, allowing developers to write methods in interfaces that have a default implementation. This was primarily introduced to enhance the Java Collections Framework but also to aid in the evolutionary design of interfaces.
For example, consider an interface Vehicle with a default method:
In this case, any class implementing Vehicle can override printVehicleType, but if it doesn't, the default method will be used, providing a fallback behavior without forcing the implementing classes to provide their own version.
Abstract Methods in Classes
Abstract methods, on the other hand, are declared without an implementation in an abstract class, and they must be implemented by any first concrete subclass of that abstract class. Abstract methods essentially set a contractual agreement that must be fulfilled by subclasses.
For instance:
Here, any subclass of AbstractVehicle needs to provide an implementation of getNumberOfWheels().
Comparison and Decision Framework
- Flexibility and Use Cases: Default methods provide high flexibility especially when adding new methods to an interface for backward compatibility. This avoids breaking existing code. Abstract methods are more rigid and are ideal when a common base behavior has to be enforced and shared across multiple subclasses.
- Contractual Agreement: Interfaces with default methods can offer optional methods that don't require implementation, whereas abstract classes enforce a contract requiring method implementations.
- Multiple Inheritance: One of the significant advantages of default methods in interfaces is support for multiple inheritance, where a class can implement multiple interfaces. Abstract classes, conversely, do not support multiple inheritance due to the "diamond problem," where a class can inherit conflicting behavior from multiple parent classes.
Here is a table summarizing the key points of both approaches:
| Feature | Interface with Default Method | Abstract Class Method |
| Implementation Optional | Yes | No |
| Support for Evolution | Better (non-breaking changes) | Limited |
| Enforcing a Contract | Weak (interfaces are contracts but with optional enforcement due to default methods) | Strong |
| Multiple Inheritance | Supported | Not supported |
| Example Use Case | Adding new features to existing interfaces without breaking existing implementations. | Base functionality that needs to be shared across all subclasses with enforced implementation requirements. |
Conclusion
In summary, the choice between using a default method in an interface and an abstract method in a class depends largely on the design requirements, the need for backward compatibility, and the specific contractual agreements you want to enforce in your application. For evolutionary designs where interfaces are already widely implemented, default methods offer a non-breaking pathway to enhance functionality. Abstract classes are more suited when starting a new family of related classes, where some common behavior needs to be enforced and shared. Each approach has its place in Java application development, and understanding their implications helps in creating more maintainable and flexible codebases.
Related reading
- When to use Mockito.verify?
- When to use RunWith and when ExtendWith
- When to use Spring Integration vs. Camel?
- When to use StringBuilder in Java
- When to use volatile with multi threading?
- When using Spring Security, what is the proper way to obtain current username (i.e. SecurityContext) information in a bean?
- When would you call java's thread.run instead of thread.start?
- When would you use a WeakHashMap or a WeakReference?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.