Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is "final" not allowed in Java 8 interface methods?

One of the most useful features of Java 8 are the new default methods on interfaces. There are essentially two reasons (there may be others) why they have been introduced:

  • Providing actual default implementations. Example: Iterator.remove()
  • Allowing for JDK API evolution. Example: Iterable.forEach()

From an API designer's perspective, I would have liked to be able to use other modifiers on interface methods, e.g. final. This would be useful when adding convenience methods, preventing "accidental" overrides in implementing classes:

interface Sender {      // Convenience method to send an empty message     default final void send() {         send(null);     }      // Implementations should only implement this method     void send(String message); } 

The above is already common practice if Sender were a class:

abstract class Sender {      // Convenience method to send an empty message     final void send() {         send(null);     }      // Implementations should only implement this method     abstract void send(String message); } 

Now, default and final are obviously contradicting keywords, but the default keyword itself would not have been strictly required, so I'm assuming that this contradiction is deliberate, to reflect the subtle differences between "class methods with body" (just methods) and "interface methods with body" (default methods), i.e. differences which I have not yet understood.

At some point of time, support for modifiers like static and final on interface methods was not yet fully explored, citing Brian Goetz:

The other part is how far we're going to go to support class-building tools in interfaces, such as final methods, private methods, protected methods, static methods, etc. The answer is: we don't know yet

Since that time in late 2011, obviously, support for static methods in interfaces was added. Clearly, this added a lot of value to the JDK libraries themselves, such as with Comparator.comparing().

Question:

What is the reason final (and also static final) never made it to Java 8 interfaces?

like image 657
Lukas Eder Avatar asked May 04 '14 06:05

Lukas Eder


People also ask

Can we have final methods in interface in Java?

No ;Interface only have abstract methods. methods. interface method can not be final .

Can we declare final variable in interface?

an interface can be empty, with no methods or variables in it. we can't use the final word in the interface definition, as it will result in a compiler error. all interface declarations should have the public or default access modifier; the abstract modifier will be added automatically by the compiler.

Why interface methods are public static and final?

because if you make a method final then you can not override it and the sole purpose of Interface is to have methods that will be overridden by all those class that implements that Interface. why can't we make Interface methods static?

Can we have final and static method in interface?

No,Because of static methods belolngs to a class not instance of class,and interfaces are not classes.In interface you define a behaviour taht has to be implemented in calss.So it is not possible to make a static method in interface.In java8 introduces static methods in interface.


2 Answers

This question is, to some degree, related to What is the reason why “synchronized” is not allowed in Java 8 interface methods?

The key thing to understand about default methods is that the primary design goal is interface evolution, not "turn interfaces into (mediocre) traits". While there's some overlap between the two, and we tried to be accommodating to the latter where it didn't get in the way of the former, these questions are best understood when viewed in this light. (Note too that class methods are going to be different from interface methods, no matter what the intent, by virtue of the fact that interface methods can be multiply inherited.)

The basic idea of a default method is: it is an interface method with a default implementation, and a derived class can provide a more specific implementation. And because the design center was interface evolution, it was a critical design goal that default methods be able to be added to interfaces after the fact in a source-compatible and binary-compatible manner.

The too-simple answer to "why not final default methods" is that then the body would then not simply be the default implementation, it would be the only implementation. While that's a little too simple an answer, it gives us a clue that the question is already heading in a questionable direction.

Another reason why final interface methods are questionable is that they create impossible problems for implementors. For example, suppose you have:

interface A {      default void foo() { ... } }  interface B {  }  class C implements A, B {  } 

Here, everything is good; C inherits foo() from A. Now supposing B is changed to have a foo method, with a default:

interface B {      default void foo() { ... } } 

Now, when we go to recompile C, the compiler will tell us that it doesn't know what behavior to inherit for foo(), so C has to override it (and could choose to delegate to A.super.foo() if it wanted to retain the same behavior.) But what if B had made its default final, and A is not under the control of the author of C? Now C is irretrievably broken; it can't compile without overriding foo(), but it can't override foo() if it was final in B.

This is just one example, but the point is that finality for methods is really a tool that makes more sense in the world of single-inheritance classes (generally which couple state to behavior), than to interfaces which merely contribute behavior and can be multiply inherited. It's too hard to reason about "what other interfaces might be mixed into the eventual implementor", and allowing an interface method to be final would likely cause these problems (and they would blow up not on the person who wrote the interface, but on the poor user who tries to implement it.)

Another reason to disallow them is that they wouldn't mean what you think they mean. A default implementation is only considered if the class (or its superclasses) don't provide a declaration (concrete or abstract) of the method. If a default method were final, but a superclass already implemented the method, the default would be ignored, which is probably not what the default author was expecting when declaring it final. (This inheritance behavior is a reflection of the design center for default methods -- interface evolution. It should be possible to add a default method (or a default implementation to an existing interface method) to existing interfaces that already have implementations, without changing the behavior of existing classes that implement the interface, guaranteeing that classes that already worked before default methods were added will work the same way in the presence of default methods.)

like image 195
Brian Goetz Avatar answered Sep 22 '22 10:09

Brian Goetz


In the lambda mailing list there are plenty of discussions about it. One of those that seems to contain a lot of discussion about all that stuff is the following: On Varied interface method visibility (was Final defenders).

In this discussion, Talden, the author of the original question asks something very similar to your question:

The decision to make all interface members public was indeed an unfortunate decision. That any use of interface in internal design exposes implementation private details is a big one.

It's a tough one to fix without adding some obscure or compatibility breaking nuances to the language. A compatibility break of that magnitude and potential subtlety would seen unconscionable so a solution has to exist that doesn't break existing code.

Could reintroducing the 'package' keyword as an access-specifier be viable. It's absence of a specifier in an interface would imply public-access and the absence of a specifier in a class implies package-access. Which specifiers make sense in an interface is unclear - especially if, to minimise the knowledge burden on developers, we have to ensure that access-specifiers mean the same thing in both class and interface if they're present.

In the absence of default methods I'd have speculated that the specifier of a member in an interface has to be at least as visible as the interface itself (so the interface can actually be implemented in all visible contexts) - with default methods that's not so certain.

Has there been any clear communication as to whether this is even a possible in-scope discussion? If not, should it be held elsewhere.

Eventually Brian Goetz's answer was:

Yes, this is already being explored.

However, let me set some realistic expectations -- language / VM features have a long lead time, even trivial-seeming ones like this. The time for proposing new language feature ideas for Java SE 8 has pretty much passed.

So, most likely it was never implemented because it was never part of the scope. It was never proposed in time to be considered.

In another heated discussion about final defender methods on the subject, Brian said again:

And you have gotten exactly what you wished for. That's exactly what this feature adds -- multiple inheritance of behavior. Of course we understand that people will use them as traits. And we've worked hard to ensure that the the model of inheritance they offer is simple and clean enough that people can get good results doing so in a broad variety of situations. We have, at the same time, chosen not to push them beyond the boundary of what works simply and cleanly, and that leads to "aw, you didn't go far enough" reactions in some case. But really, most of this thread seems to be grumbling that the glass is merely 98% full. I'll take that 98% and get on with it!

So this reinforces my theory that it simply was not part of the scope or part of their design. What they did was to provide enough functionality to deal with the issues of API evolution.

like image 27
Edwin Dalorzo Avatar answered Sep 21 '22 10:09

Edwin Dalorzo