Статьи

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

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

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

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

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

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

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

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

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

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

1
2
3
4
5
6
7
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

Или также …

Я знаю, что у нас уже был очень полезный разговор об этом, но только для того, чтобы напомнить другим людям в этой теме: большая часть дебатов вокруг «финала» зависит от контекста: это публичный API или это внутренний код? В первом контексте я согласен, что есть несколько хороших аргументов для финала. В последнем случае final почти всегда является ПЛОХОЙ идеей. Чарльз Рот в нашем блоге

Все эти аргументы имеют тенденцию идти в одном направлении: «Мы работаем над дрянным кодом, поэтому нам нужен хотя бы какой-то обходной путь, чтобы облегчить боль».

Но почему бы не подумать об этом так:

Разработчики API, которые имеют в виду все вышеперечисленные люди, создадут именно тот ужасный API, который вы хотели бы патчить через расширение. По совпадению, тот же самый дизайнер API не будет размышлять о полезности и коммуникативности ключевого слова final и, следовательно, никогда не будет использовать его, если этого не требует язык Java. Беспроигрышный вариант (хотя и дрянной API, шаткие обходные пути и патчи).

Разработчики API, которые хотят использовать final для своих API, будут много размышлять о том, как правильно проектировать API (и четко определенные точки расширения / SPI), так что вы никогда не будете беспокоиться о том, что что-то будет final . Опять же, беспроигрышный (и потрясающий API).

Плюс, в последнем случае, странный хакер будет защищен от взлома и взлома вашего API таким образом, что это приведет только к боли и страданиям, но это на самом деле не потеря.

Окончательные методы интерфейса

По вышеупомянутым причинам я все еще глубоко сожалею о том, что final невозможен в интерфейсах Java 8. Брайан Гетц дал превосходное объяснение, почему так принято. На самом деле обычное объяснение. Тот, который не является главной целью дизайна для изменений!

Но подумайте о последовательности, регулярности языка, если бы мы имели:

1
2
3
4
5
default interface ImplementableInterface {
            void abstractMethod   () ;
            void finalMethod      () {}
    default void overridableMethod() {}
}

(Утки и бега…)

Или, более реалистично, с нашим статус-кво по default по default :

1
2
3
4
5
interface ImplementableInterface {
          void abstractMethod   () ;
    final void finalMethod      () {}
          void overridableMethod() {}
}

в заключение

Итак, еще раз, каковы ваши (последние) мысли по этому обсуждению?

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

Ссылка: Это финальная дискуссия! от нашего партнера JCG Лукаса Эдера в блоге JAVA, SQL и JOOQ .