Соглашение об именах получателей / установщиков Post Java-14

В Java 14 появилась функция записи. Запись создает получатель с тем же именем, что и поле, поэтому можно было бы написатьprint(person.name())например. Но старое соглашение о компонентах Java требует, чтобы этот метод называлсяgetName().

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

Есть ли какие-либо официальные или полуофициальные рекомендации, как называть геттеры и сеттеры после Java 14 в новом коде?

5 ответов

Решение

Цитата из JEP 359:

Это не цель объявить "войну шаблону"; в частности, не ставится цель решить проблемы изменяемых классов с помощью соглашений об именах JavaBean.

Мое понимание, основанное на том же документе, что записи являютсяtransparent holders for shallowly immutable data.

Что, как говорится:

  1. Записи - не то место, где искать синтаксический сахар геттеров / сеттеров, поскольку они не предназначены для замены JavaBeans.
  2. Я полностью согласен с вами в том, что JavaBeans слишком многословны. Возможно, можно было бы реализовать дополнительную функцию (называемую beans вместо записей) - очень похожее поведение с функцией записи, но это позволило бы изменять. В этом случае записи и bean-компоненты не будут взаимоисключающими.
  3. Как уже упоминалось, записи находятся в режиме предварительного просмотра. Посмотрим, какие будут отзывы от сообщества.

В общем, ИМХО, это шаг вперед... Я написал этот набор примеров, где вы можете увидеть сокращение кода до ~15% LOC от стандартных JavaBeans.

Также обратите внимание, что records behave like normal classes: they can be declared top level or nested, they can be generic, they can implement interfaces(из того же документа). Фактически вы можете частично смоделировать JavaBeans (хотя имели бы смысл только геттеры), извлекая интерфейс, содержащий геттеры, однако это было бы много работы и не очень чистое решение...

Итак, исходя из приведенной выше логики, чтобы ответить на ваш вопрос, нет - я не видел никаких (полу) официальных рекомендаций для геттеров и сеттеров, и я не думаю, что сейчас для этого есть мотивация, потому что, опять же, записи не заменяют JavaBeans...

Спецификация теперь является «окончательной» для Java 17, и это несоответствие соглашения об именах, к сожалению, не устранено. Я наткнулся на него, когда пытался использовать записи как классы мелких держателей для реализации интерфейсов, являющихся частью существующей модели предметной области.

Хотя это не такое изящное решение, как хотелось бы, записи могут иметь методы, так что вы можете добавить «устаревшие» геттеры к своим , как в следующем (надуманном, но простом) примере.

      public interface Nameable {
   public String getName();
}

public record Person(String name) implements Nameable {
   public String getName() {
      return name;   // or return name();
   }
}

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

Можно сказать, что разработчики языка выполнили свою задачу «не объявлять войну шаблонным»

Я решил остановиться на одном негласном предположении: руководства по стилю, которые мы сейчас имеем, на самом деле рекомендуют геттеры и сеттеры в стиле Bean.

Ни одно из руководств по стилю, которые я нашел, на самом деле не рекомендует это делать. Один из них отмечает, что мнения по этому вопросу разделились. Таким образом, если вы используете соглашениеfoo()иfoo(newValue), вы будете соответствовать легкодоступным руководствам по стилю.

Путеводители

Руководство по стилю Google Java действительно показывает некоторыеgetFieldметоды, но в фактическом руководстве они не упоминаются.

Браун тоже заимствует у Google.

Корнелл говорит:

Однако соглашение в Java заключается в том, что функция, которая возвращает значение поля (скажем, заголовок), представляет собой имя поля, которому предшествует «get». У людей по этому поводу двоякое мнение; не все думают, что это хорошая идея. Также можно использовать название «титул».

Соглашения Java такие же, как у Google.

Eydean, как и Google, заимствует значительные средства у Google и Sun.

Twitter заимствует у Google, так же, как и Google.

И, наконец, в §8.3.1спецификации Java Beans указано, как именно называть геттеры и сеттеры, чтобы они были совместимы с Beans:

Простые свойства. По умолчанию мы используем шаблоны проектирования для поиска свойств путем поиска методов формы:

       public <PropertyType> get<PropertyName>();
public void set<PropertyName>(<PropertyType> a);

Если мы обнаружим совпадающую пару методов «get< PropertyName >» и «set< PropertyName >», которые принимают и возвращают один и тот же тип, то мы рассматриваем эти методы как определение свойства для чтения и записи, имя которого будет «< propertyName >». . Мы будем использовать метод «get<PropertyName> » для получения значения свойства и метод «set<PropertyName> » для установки значения свойства. Пара методов может находиться либо в одном классе, либо один может находиться в базовом классе, а другой — в производном классе.

И даже если вы совершенно не обращаете на это внимания:

§ 8.6 Java Bean также может явно указывать, какие свойства, события и методы он поддерживает, предоставляя класс, реализующий интерфейс BeanInfo.

Я наткнулся на это, исследуя соглашения об именах для своего проекта. Глядя на «последние» дополнения к стандартной библиотеке (например, Path, FileSystem, HttpRequest,...), единственный более или менее «шаблон», который я мог обнаружить, заключался в том, что подразумевает прямой, немодифицированный доступ к значению поля и, таким образом, существование поля именно с этим типом.

Принимая во внимание, что «getXXX» означает, что вы не можете/не должны предполагать существование поля. Это свойство может быть вычисляемым, иметь прямой доступ к полю или быть обернуто только для чтения (например,List.copyOf) или преобразованы.

Итак, мой вывод: если вы хотите сообщить «структуру» или обеспечить приоритетность использования полей.prop(). Во всех остальных случаях придерживайтесьgetXXXпоскольку он более гибкий (реализаторами могут быть классы сущностей, записи или классы обслуживания.

Кстати: я знаю, что даже в jdk есть большие нарушители этой логики. напримерBigDecimalвот почему я сосредоточился на более поздних дополнениях.

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

В классах Java объектные поля могут быть частными или общедоступными. В последнем типе поля их можно получить или установить, просто добавив точку и имя поля, например

 Employee emp = new Employee(); // Nullary constructor
 emp.name = "John Schmidt";     // Setter
 . . . 
 . . . 
 if (emp.name != "Buddy")       // Getter
 {
    emp.bonus = 100.00;
 }

Неприватные поля часто используются в приложениях Android для экономии памяти и времени на извлечение данных. Но нет причин не использовать их в Java, где это безопасно.

Теперь, если вы измените обычный способ в классах Java на что-то вроде того, что используется в типах записей, например

String name = emp.name();  // New getter convention for private field

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

И если вы измените геттер записи на то, что используется в объектах Java, т.е.

obj.getField()

тогда существует риск запутать рецензентов кодировщика, и, возможно, компилятор может рассматривать его как объект Java, в зависимости от критериев принятия решения.

Короче говоря, это объект другого типа по сравнению с обычным классом или перечислением Java. Его методы доступа однозначно указывают на этот новый тип. Во всяком случае, я так это вижу. Может быть, кто-нибудь из комитета по разработке Java сможет просветить нас дальше.

Другие вопросы по тегам