Статьи

Это финальная дискуссия!

Пун намеревался… Давайте обсудим Java  final.

Недавно наш популярный пост в блоге  «10 тонких передовых методов при кодировании Java» получил значительное возрождение и новый набор комментариев, поскольку он был  обобщен и связан с JavaWorld . В частности, редакторы JavaWorld оспорили наше мнение о ключевом слове Java « final«:

Более спорно, Эдер берет на себя вопрос о ли это когда-нибудь безопасно сделать методы конечных по умолчанию:

«Если вы полностью контролируете весь исходный код, нет ничего плохого в том, чтобы сделать методы финальными по умолчанию, потому что:»

  • «Если вам нужно переопределить метод (правда?), Вы все равно можете удалить ключевое слово final»
  • «Вы никогда не будете случайно отменять любой метод»

Да, в самом деле. Все классы, методы, поля и локальные переменные должны быть окончательными по умолчанию и изменяемыми через ключевое слово.

Вот поля и локальные переменные:

int finalInt  = 1;
val int finalInt  = 2;
var int mutableInt = 3;

Вопрос о val том, действительно ли необходимо ключевое слово в стиле Scala / C #, спорен  . Но ясно, чтобы снова модифицировать поле / переменную, у нас должно быть ключевое слово, явно позволяющее это сделать. То же самое для методов — и я использую default ключевое слово Java 8  для улучшения согласованности и регулярности:

class FinalClass {
    void finalMethod() {}
}
default class ExtendableClass {
    void finalMethod  () {}
    default void overridableMethod() {}
}

По нашему мнению, это был бы идеальный мир, но Java идет другим путем, делая  default (переопределяемым, изменяемым) значение по умолчанию и  final (не переопределяемым, неизменным) явную опцию.

Справедливо, мы будем жить с этим

… И как разработчики API (  конечно  , из jOOQ API), мы просто с радостью разместим  final повсеместно, чтобы хотя бы притвориться, что Java имеет более разумные значения по умолчанию, упомянутые выше.

Но многие люди не согласны с этой оценкой, в основном по той же причине:

Как человек, который работает в основном в среде OSGI, я не могу не согласиться, но можете ли вы гарантировать, что другой дизайнер API чувствовал то же самое? Я думаю, что лучше предупреждать ошибки разработчиков API, чем предупреждать ошибки пользователей, устанавливая ограничения на то, что они могут расширять по умолчанию. —  eliasv на Reddit

Или…

Сильно не согласен. Я бы предпочел запретить окончательный и частный доступ к публичным библиотекам. Такая боль, когда мне действительно нужно что-то расширить, а это невозможно.

Преднамеренная блокировка кода может означать две вещи: либо отстой, либо безупречна. Но если он идеален, то никому не нужно его расширять, так почему вас это волнует?

Конечно, существуют веские причины использовать final, но боязнь взломать кого-либо новой версией библиотеки не является одной из них. —  meotau на reddit

Или также …

I know we’ve had a very useful conversation about this already, but just to remind other folks on this thread: much of the debate around ‘final’ depends on the context: is this a public API, or is this internal code? In the former context, I agree there are some good arguments for final. In the latter case, final is almost always a BAD idea. – Charles Roth on our blog

All of these arguments tend to go into one direction: “We’re working on crappy code so we need at least some workaround to ease the pain.”

But why not think about it this way:

The API designers that all of the above people have in mind will create precisely that horrible API that you’d like to patch through extension. Coincidentally, the same API designer will not reflect on the usefulness and communicativeness of the keyword final, and thus will never use it, unless required by the Java language. Win-win (albeit crappy API, shaky workarounds and patches).

The API designers that want to use final for their API will reflect a lot on how to properly design APIs (and well-defined extension points / SPIs), such that you will never worry about something being final. Again, win-win (and an awesome API).

Plus, in the latter case, the odd hacker will be kept from hacking and breaking your API in a way that will only lead to pain and suffering, but that’s not really a loss.

Final interface methods

For the aforementioned reasons, I still deeply regret that final is not possible in Java 8 interfaces. Brian Goetz has given an excellent explanationwhy this has been decideed upon like that. In fact, the usual explanation. The one about this not being the main design goal for the change 😉

But think about the consistency, the regularity of the language if we had:

default interface ImplementableInterface {
    void abstractMethod  () ;
    void finalMethod  () {}
    default void overridableMethod() {}
}

(Ducks and runs…)

Or, more realistically with our status quo of defaulting to default:

interface ImplementableInterface {
    void abstractMethod  () ;
    final void finalMethod  () {}
    void overridableMethod() {}
}

Finally

So again, what are your (final) thoughts on this discussion?

If you haven’t heard enough, consider also reading this excellent post by Dr. David Pearce, author of the whiley programming language