7

I know this question has been asked many times and we have articles all over the internet but I still cannot fully understand, when should I use interface or abstract class since I am using Java 15.

Most of the articles talk about the differences and use cases before Java 8 which makes sense but not when you can basically provide body for your methods in interface.

The only thing that made sense to me is non-public and non-final restrictions.

I would really appreciate if somebody can point out 1-2 examples of the scenarios where I need to choose between interface and abstract class in Java 15. Also, would be great if it can be in terms of real life projects rather than Animal or shape class examples.

Thanks !!

newLearner
  • 637
  • 1
  • 12
  • 20
  • https://stackoverflow.com/q/10040069/10292075 – Yoshikage Kira Jun 28 '21 at 22:43
  • Abstract classes have constructors and can implement interfaces themselves (all sub-classes will inherit those interfaces), so they are more useful as pillars at the foundations of your architecture. – pcalkins Jun 28 '21 at 23:16
  • You use interfaces to specify incoming data, eg parameters to a method. You use classes to implement interfaces; abstract classes to implement base behavior for several classes. – daniu Jun 29 '21 at 21:36

1 Answers1

7

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 an UnsupportedOperationException 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.
  • 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.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • 1
    Hey, thanks for the answer. I understood the crux of the problem but this does not answer my question exactly. What would be the real life scenario where I would have to "choose" between interface or abstract class. – newLearner Jun 29 '21 at 19:46
  • @newLearner I added a section at bottom to address choosing. Thanks for the feedback. – Basil Bourque Jun 29 '21 at 21:11
  • Default implementations on interfaces were not implemented as some kind of backward compatibility hack. Like many newer Java features (lambdas, SAM conversion, records, etc.), they were taken for a test run in Scala (then later Kotlin) and everyone loved them, so they got backported to Java. It's a genuinely useful, well-defined language feature, not some behind-the-scenes trickery. – Silvio Mayolo Jun 29 '21 at 21:45
  • @SilvioMayolo Brian Goetz has said publicly multiple times that `default` on interfaces was added at that time to support evolution of existing interfaces to support lambda/streams features. I added links to two primary sources in my Answer. – Basil Bourque Jun 29 '21 at 23:12
  • I can't thank you enough for taking time out and giving such a detailed answer. Really appreciate your efforts ! – newLearner Jun 30 '21 at 21:16