When to use: Java 8+ interface default method, vs. abstract method
There's a lot more to abstract classes than default method implementations (such as private state), but as of Java 8, whenever you have the choice of either, you should go with the defender (aka. default
) method in the interface.
The constraint on the default method is that it can be implemented only in the terms of calls to other interface methods, with no reference to a particular implementation's state. So the main use case is higher-level and convenience methods.
The good thing about this new feature is that, where before you were forced to use an abstract class for the convenience methods, thus constraining the implementor to single inheritance, now you can have a really clean design with just the interface and a minimum of implementation effort forced on the programmer.
The original motivation to introduce default
methods to Java 8 was the desire to extend the Collections Framework interfaces with lambda-oriented methods without breaking any existing implementations. Although this is more relevant to the authors of public libraries, you may find the same feature useful in your project as well. You've got one centralized place where to add new convenience and you don't have to rely on how the rest of the type hierarchy looks.
Java 8 -- interfaces with default methods vs abstract classes
Here are some reasons to choose an abstract class over an interface. The ones you list - private fields, etc., are some of the major ones. These are a few more subtle ones
- Type clarity. You can only extend one class. This makes it clearer what your object is an how to use it.
- The diamond problem. You have to implement all of the default methods in an interface to help avoid the diamond problem. If the interface is Collections, this can be a huge pain since there are a billion of them. With an abstract class, you only overwrite what you need to
- In Java 8, there are lambda expressions, and the old routine of passing around an interface with a method to implement has been usurped. Still, when you see an interface with a default method, this can interpreted in ways you might not intend
Here's what Oracle has to say on the subject:
Which should you use, abstract classes or interfaces?
Consider using abstract classes if any of these statements apply to
your situation:
- You want to share code among several closely related classes.
- You expect that classes that extend your abstract class have many common methods or fields, or require access modifiers other than
public (such as protected and private).- You want to declare non-static or non-final fields. This enables you to define methods that can access and modify the state of the
object to which they belong.
In this article, Orace defends the distinction between the two type systems
https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html
EDIT To clarify the "diamond problem" bullet
The problem is described here (and many other places)
http://www.lambdafaq.org/what-about-the-diamond-problem/
The problem occurs when you inherit from two places that declare the same method, and you have to pick one when resolving a function call. This was never an issue in Java 7-, since you could only extend one class and interfaces had no methods.
The resolution tactic now is a little complicated, but here is a good description of it:
(from http://blog.loxal.net/2013/05/java-8-default-interface.html)
To address the diamond problem there is a precedence in which order an
implementation is used: only if the class implements all default /
optional methods of its interfaces, the code can be compiled and the
implementations of this class are used. Otherwise the compiler tries
to patch the missing implementation(s) with interface's default
implementation. And if there are multiple default implementations of a
method, then the diamond problem occurs and the compiler rejects the
compilation. Also if the class implements an interface's default
method, the implementation of the class will be used instead of
interfaces's default implementation.
If you stick to abstract classes, you will never run into this problem. However, if your object is required to implement two interfaces (because it needs to be added to lists that are expecting those types, e.g.), and those interfaces have conflicting method signatures, you will wind up having to redefine a whole bunch of methods even if that means you're just making super calls, which sort of defeats the point of inheritance-based dynamic dispatch. It isn't a deal-breaker, but something to consider when structuring a complex Java project
Java 8 default methods vs. non-abstract methods in abstract classes
non-abstract methods in abstract classes will be called when it's concrete subclass calls super() if it is overridden. So there are multiple possibilities. If method is not overridden then the super class method will be executed. if we use super() in the concrete subclass method then the overridden method with the super class method will be executed.
Where as Java 8 interface default methods are completely different. It provided a choice to the developers to implement the method in the implementing class or not. If the function is not implemented then and only then the default method will be executed.
Possible Use Case :
The most important use case for this new feature in the JDK libraries is the possibility to extend existing interfaces without breaking existing implementers: adding a new abstract method to an interface would require all implementing classes to implement that new method.(Source)
Java 8 Interface vs Abstract Class
That sentence means that a default
method is implemented inside an interface, so it doesn't have any access to a real state of an object but just to what the interface itself exposes, since an interface can't declare instance variables.
For example:
abstract class Foo {
int result;
int getResult() { return result; }
}
This can't be done in an interface
because you can't have any member variable. The only thing you can do is to combine multiple interface methods, which is what it is specified as convenience / higher-level methods, eg:
interface Foo {
void preProcess();
void process();
void postProcess();
default void processAll() {
preProcess();
process();
postProcess();
}
}
When to use interface vs abstract class after Java 8
default
methods on interface
Apparently you are referring to the feature of “default methods” implementing behavior in an interface.
You should understand that the feature was added as a way around this dilemma: How to retroactively add features leveraging streams and lambda on existing interfaces without breaking existing classes that implement those interfaces?
Many new methods were added to those interfaces such as in the Java Collections Framework. Adding methods to an existing interface would automatically break all classes implementing the interface that are lacking the newly-required methods. Being able to provide a fallback, to give an implementation where one is now required but not yet existing, would resolve the dilemma. Thus « default methods » were born.
To quote from the Oracle tutorial linked above:
Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces.
To quote this Answer by Brian Goetz, Java Language Architect at Oracle:
The proximate reason for adding default methods to interfaces was to support interface evolution
So this feature of adding default behavior to an interface was not meant to be a new mainstream feature in and of itself. The intent of default
was not to replace abstract
.
Indeed, some experienced Java experts have recommended against making a habit of writing default methods on an interface. They recommend pretty much ignoring that feature of the Java language. Continue to think of interfaces as simply defining a contract, and abstract classes as providing partial implementations meant to be completed in a subclass.
You are certainly free to write your own default methods on your interfaces. And certainly you should do so if you are in a similar situation of having published an interface that others may have implemented, and now you want to add methods. But unnecessarily adding default methods is likely to confuse other programmers who expect partial implementations on an abstract class rather than an interface.
Four situations calling for default
method on an interface
In that same post linked above, Brian Goetz suggests three other cases beyond interface evolution where default methods on an interface may be appropriate. Here is a quick mention; see his post for details.
- Optional methods - The
default
method throws anUnsupportedOperationException
because we expect implementations of this interface to more often not want to implement this method. - Convenience methods
- Combinators
Start with interface, move to abstract class for shared code
As for choosing between an interface and abstract class:
- Generally start with an interface. Or several interfaces if you want various implementing classes to mix various contracts (see mixin).
- Think twice before adding a
default
method. Consider if your situation meets one of the four cases recommended by Brian Goetz as discussed above.
- Think twice before adding a
- If you come to realize that you have duplicated code across multiple classes, then consider centralizing that shared code to an abstract class to be used across subclasses.
- Alternatively, use composition rather than inheritance (discussed below).
For example, you might have a class for domestic ShippingLabelUS
as well as ShippingLabelCanada
and ShippingLabelOverseas
. All three need to convert between imperial pounds and metric kilograms. You find yourself copying that code between the classes. At this point you might consider having all three classes extend from abstract class ShippingLabel
where a single copy of the weight conversion methods live.
While designing your API keep in mind that Java, like most OOP languages, has single-inheritance. So your subclasses are limited to extending only one class. To be a bit more specific about the single-versus-multiple inheritance, I will quote Brian Goetz from this PDF of a slide deck:
[regarding
default
methods on an interface]Wait,is this multiple inheritance in Java?
• Java always had multiple inheritance of types
• This adds multiple inheritance of behavior
• But not of state, where most of the trouble comes from
Composition over inheritance
An alternative to using an abstract class for shared behavior is creating a separate class for specific behavior, then adding an object of that separate class to be kept as a member field on the larger class. Wise programmers often share this pearl of wisdom: Prefer composition over inheritance.
Regarding the shipping label example above, you could create a WeightConverter
class, an object of which would be a member of each of the three label classes. In this arrangement, no need for the abstract class.
Does Java have plan that default method (java8) Substitute for Abstract Class?
Default methods can't substitute abstract classes, as abstract classes can (and often do) have fields. Interfaces can only contain behaviour and not state, which is unlikely to change in the future as multiple inheritance of state in Java is seen (rightly or wrongly) as evil.
They can also have final
methods, which is another thing you can't mimic with default
methods.
If anything, interfaces with default methods resemble traits rather than abstract classes, but the match isn't perfect. Using interfaces as traits is something that has to be done very carefully and knowing the limitations they come with. (Such as any implementing class can override a default
method, potentially ruining the trait.)
Is Interface remain fully abstract after adding default method in java 1.8?
Even if you have only one default method in your interface, it will be abstract. You will have to provide implementing class to instantiate an object. Note that default
methods added in Java 8 has special purpose. From Java doc:
Default methods enable you to add new functionality to the interfaces
of your libraries and ensure binary compatibility with code written
for older versions of those interfaces.
So you should use default
methods judiciously.
Related Topics
How to Set or Change the Default Java (Jdk) Version on Macos
How to Run Test Methods in Specific Order in Junit4
Is It Safe to Use a Static Java.Sql.Connection Instance in a Multithreaded System
Why Does Java Have Transient Fields
"Invalid Signature File" When Attempting to Run a .Jar
The Difference Between Classes, Objects, and Instances
Convert String to Double in Java
Java Error: Comparison Method Violates Its General Contract
Difference Between Jdk and Jre
Getting the Name of the Currently Executing Method
Difference Between a Static Method and a Non-Static Method
Changing the Current Working Directory in Java
How to Get the Current Date and Time in Utc or Gmt in Java