Почему Alibaba запрещает разработчикам использовать isSuccess в качестве имени переменной (исправленная версия)

Java

В повседневной разработке мы часто определяем переменные логического типа в классах, например, предоставляяRPCКогда используется интерфейс, мы обычно определяем поле, чтобы указать, был ли запрос успешным.

По поводу определения поля "успешен ли этот запрос" тут на самом деле много всяких внимания и ям.Небольшая невнимательность попадет в яму.Автор уже давно сталкивался с подобными проблемами,и эта статья здесь ... Простой анализ вокруг этого. В конце концов, как определить переменную-член логического типа.

В общем, мы можем определить переменную-член логического типа следующими четырьмя способами:

boolean successboolean isSuccessBoolean successBoolean isSuccessскопировать код

Какое из приведенных выше четырех определений чаще всего используется в вашем повседневном развитии? Какую позу использовать правильно?

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

Кроме того, первый и третий типы переменных именуются успехом при определении переменных, а два других именуются с помощью isSuccess.

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

успех или успех

Должен ли я использовать успех или isSuccess для именования переменных? С семантической точки зрения оба метода именования можно объяснить, и здесь нет двусмысленности. Итак, на какие еще принципы мы можем ссылаться, чтобы позволить себе делать выбор?

В руководстве по разработке Java для Alibaba есть «обязательное» правило на этот счет:

 Итак, почему существует такое положение? Давайте посмотрим на разницу между именами переменных логического типа в POJO.

class Model1  {   private Boolean isSuccess;   public void setSuccess(Boolean success) {       isSuccess = success;   }   public Boolean getSuccess() {       return isSuccess;   }}class Model2 {   private Boolean success;   public Boolean getSuccess() {       return success;   }   public void setSuccess(Boolean success) {       this.success = success;   }}class Model3 {   private boolean isSuccess;   public boolean isSuccess() {       return isSuccess;   }   public void setSuccess(boolean success) {       isSuccess = success;   }}class Model4 {   private boolean success;   public boolean isSuccess() {       return success;   }   public void setSuccess(boolean success) {       this.success = success;   }}скопировать код

Сеттер/геттер приведенного выше кода автоматически генерируется Intellij IDEA.Если вы внимательно наблюдаете за приведенным выше кодом, вы найдете следующие правила:

  • Методы получения и установки автоматически генерируются базовым типом, имена обаisXXX()иsetXXX()Форма.

  • Методы получения и установки автоматически генерируются типом оболочки, оба имениgetXXX()иsetXXX()Форма.

Теперь, когда мы пришли к соглашению об использовании базового логического типа для определения переменных-членов, давайте посмотрим на разницу между сеттерами и геттерами в Model3 и Model4.

Мы можем обнаружить, что хотя имена переменных-членов в Model3 и Model4 различны, одна из них — success, а другая — isSuccess, но их автоматически сгенерированные имена методов получения и установки совпадают.isSuccessиsetSuccess.

Спецификация сеттера/геттера в Java Bean

Определение метода получения/установки в Java Bean на самом деле четко определено.Согласно спецификации JavaBeans(TM), если это обычный параметр с именем propertyName, его установка/получение должны быть определены следующими способами:

public <PropertyType> get<PropertyName>();public void set<PropertyName>(<PropertyType> a);скопировать код

Однако логическая переменная propertyName имеет другой набор принципов именования:

public boolean is<PropertyName>();public void set<PropertyName>(boolean m);скопировать код

Сравнив эту спецификацию JavaBeans, мы обнаружили, что в Model4 имя переменной isSuccess, если она определена строго в соответствии со спецификацией, его метод получения должен называться isIsSuccess. Но многие IDE будут генерировать isSuccess по умолчанию.

Так в чем проблема это сделать.

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

Влияние сериализации

Информацию о сериализации и десериализации см.Сериализация и десериализация объектов Java. Давайте возьмем в качестве примера более часто используемую сериализацию JSON, чтобы увидеть разницу между часто используемыми fastJson, jackson и Gson:

/**

* @author Hollis

*/

public class BooleanMainTest {   public static void main(String[] args) throws IOException {       //定一个Model3类型       Model3 model3 = new Model3();       model3.setSuccess(true);       //使用fastjson(1.2.16)序列化model3成字符串并输出       System.out.println("Serializable Result With fastjson :" + JSON.toJSONString(model3));       //使用Gson(2.8.5)序列化model3成字符串并输出       Gson gson =new Gson();       System.out.println("Serializable Result With Gson :"+gson.toJson(model3));       //使用jackson(2.9.7)序列化model3成字符串并输出       ObjectMapper om = new ObjectMapper();       System.out.println("Serializable Result With jackson :" +om.writeValueAsString(model3));   }}class Model3 implements Serializable {   private static final long serialVersionUID = 1836697963736227954L;   private boolean isSuccess;   public boolean isSuccess() {       return isSuccess;   }   public void setSuccess(boolean success) {       isSuccess = success;   }   public String getHollis(){       return "hollischuang";   }}
скопировать код

В Model3 приведенного выше кода есть только одна переменная-член, isSuccess, и три метода: isSuccess и setSuccess, автоматически сгенерированные для нас IDE, а другой — метод, добавленный автором, который соответствует соглашению об именах геттеров. .

Вывод приведенного выше кода:

Serializable Result With fastjson :{"hollis":"hollischuang","success":true}Serializable Result With Gson :{"isSuccess":true}Serializable Result With jackson :{"success":true,"hollis":"hollischuang"}скопировать код

В результатах fastjson и jackson поле isSuccess в исходном классе сериализуется в успех, а также содержит значение hollis. А в Gson есть только поле isSuccess.

Можно сделать вывод, что когда fastjson и jackson сериализуют объекты в json-строки, они проходят через рефлексию все геттер-методы в классе, чтобы получить getHollis и isSuccess, и тогда по правилам JavaBeans он будет думать, что это два значения Холлис свойства и успех. Сериализировать прямо в json:

{“hollis”:”hollischuang”,”success”:true}скопировать код

Но Gson этого не делает, он проходит через рефлексию по всем свойствам в классе и сериализует их значения в json:

{“isSuccess”:true}скопировать код

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

Сериализация getHollis, упомянутая выше, предназначена только для иллюстрации разницы в стратегиях сериализации между fastjson, jackson и Gson. Давайте пока отложим его в сторону. После того, как мы удалим его из Model3, повторно выполнив приведенный выше код, получили ответ:

Serializable Result With fastjson :{"success":true}Serializable Result WithGson :{"isSuccess":true}Serializable Result With jackson :{"success":true}скопировать код

Теперь содержимое json, полученное разными фреймворками сериализации, неодинаково Что произойдет, если я использую fastjson для сериализации одного и того же объекта, а затем использую Gson для его десериализации?

public class BooleanMainTest {   public static void main(String[] args) throws IOException {       Model3 model3 = new Model3();       model3.setSuccess(true);       Gson gson =new Gson();       System.out.println(gson.fromJson(JSON.toJSONString(model3),Model3.class));   }}class Model3 implements Serializable {   private static final long serialVersionUID = 1836697963736227954L;   private boolean isSuccess;   public boolean isSuccess() {       return isSuccess;   }   public void setSuccess(boolean success) {       isSuccess = success;   }   @Override   public String toString() {       return new StringJoiner(", ", Model3.class.getSimpleName() + "[","]")           .add("isSuccess=" + isSuccess)           .toString();   }}скопировать код

Вывод приведенного выше кода:

Model3[isSuccess=false]скопировать код

Это прямо противоположно тому, что мы ожидали Причина в том, что инфраструктура JSON находит метод isSuccess после сканирования всех геттеров, а затем, в соответствии со спецификацией JavaBeans, анализирует успех имени переменной и сериализует объект модели в строку. с содержанием как{"success":true}.

в соответствии с{"success":true}После синтаксического анализа этой строки json платформа Gson ищет атрибут успеха в классе Model посредством отражения, но в классе Model есть только атрибут isSuccess, поэтому в конечном десериализованном объекте класса Model isSuccess будет использовать значение по умолчанию значение ложного.

но,Как только приведенный выше код появляется в производственной среде, это определенно фатальная проблема.

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

Таким образом, переменная-член в этом классе — это успех, а метод-получатель — isSuccess, что полностью соответствует спецификации JavaBeans. Независимо от среды сериализации результат выполнения одинаков. Эта проблема избегается из источника.

Цитирование оценки Университета R по этому положению в Руководстве по разработке Java для Alibaba.

(https://woowowoo.direct call.com/question/55642203):

Итак,При определении логических переменных в POJO не используйте форму isSuccess, а используйте непосредственно успех!

Булево или логическое?

Мы уже объясняли, как выбирать между success и isSuccess, поэтому после исключения неправильного ответа остаются варианты:

boolean successBoolean successскопировать код

Итак, следует ли использовать Boolean или boolean для получения логической переменной?

Мы знаем, что boolean — это базовый тип данных, а Boolean — это тип-оболочка. Для взаимосвязи и различий между базовыми типами данных и классами-оболочками см.Статья, чтобы понять, что такое автоматическая распаковка в Java

Итак, при определении переменной-члена лучше использовать тип-оболочку или использовать примитивный тип данных?

Давайте посмотрим на простой фрагмент кода

/*** @author Hollis*/public class BooleanMainTest {   public static void main(String[] args) {       Model model1 = new Model();       System.out.println("default model : " + model1);   }}class Model {   /**    * 定一个Boolean类型的success成员变量    */   private Boolean success;   /**    * 定一个boolean类型的failure成员变量    */   private boolean failure;   /**    * 覆盖toString方法,使用Java 8 的StringJoiner    */   @Override   public String toString() {       return new StringJoiner(", ", Model.class.getSimpleName() + "[","]")           .add("success=" + success)           .add("failure=" + failure)           .toString();   }}скопировать код

Вывод приведенного выше кода:

default model : Model[success=null, failure=false]скопировать код

Видно, что когда мы не устанавливаем значение поля объекта Model, переменной типа Boolean будет установлено значение по умолчаниюnull, а переменная логического типа установит значение по умолчанию равнымfalse.

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

В Руководстве по разработке Java для Alibaba также есть некоторые правила выбора типа переменных в POJO:

Здесь предлагается использовать типы-оболочки, почему?

В качестве примера вычета мы делаем систему вычета.При вычете комиссии нам нужно прочитать значение ставки из внешней системы ценообразования.Мы ожидаем, что возвращаемое значение этого интерфейса будет содержать поле ставки с плавающей запятой. Когда мы получаем это значение, мы используем формулу: сумма * ставка = стоимость для расчета, и результат расчета вычитается.

Если биллинговая система ненормальна, она может вернуть значение по умолчанию.Если поле имеет тип Double, значение по умолчанию равно null, а если поле имеет тип double, значение по умолчанию равно 0.0.

Если система вывода не выполняет специальной обработки возвращаемого значения ставки, она напрямую сообщит об ошибке и заблокирует программу, если получит для расчета нулевое значение. Если вы получаете 0,0, вы можете рассчитать его напрямую и вычесть комиссию после того, как интерфейс станет 0. Такие аномалии не могут быть восприняты.

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

Именно поэтому рекомендуется использовать типы-оболочки в возвращаемом значении POJO и RPC.

При анализе предыдущей статьи точка зрения автора заключается в том, что для переменных логического типа я думаю, что их можно отличить от других типов, и автор не считает, что использование null для вызова NPE является лучшей практикой. Поскольку логический тип имеет только два значения, true/false, мы можем договориться с внешним вызывающим кодом о явной семантике, когда возвращаемое значение равно false.

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

Позже у автора была битва 1 на 1 (цин) (цзяо) наедине с автором «Руководства по разработке Java для Alibaba» и «Эффективность кода». наконец пришли к единому мнению,Или попробуйте использовать тип упаковки.

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

Что не так с нулем?

nullочень неоднозначно и часто может привести к путанице, и трудно определить, следует ли возвращатьnullчто это означает.

Лауреат премии Тьюринга Тони Хоар однажды публично выразилnullэто плохой дизайн.

Я называю нулевые ссылки своей ошибкой на миллиард долларов. Он был изобретен в 1965 году, когда я разработал первую комплексную систему ссылочных типов на объектно-ориентированном языке (ALGOL W). Я намерен убедиться, что все используемые ссылки абсолютно безопасны, и компилятор проверит их автоматически. Но я не мог устоять перед искушением включить ссылку Null просто потому, что ее так легко реализовать. Это привело к бесчисленным ошибкам, ошибкам и системным сбоям, которые могут стоить миллиарды долларов в течение следующих 40 лет.

Когда мы разрабатываем интерфейс, старайтесь избегать использования логического типа для определения возвращаемого значения интерфейса. В большинстве случаев, когда другие используют возвращаемое значение нашего интерфейса, они могут использоватьif(response.isSuccess){}else{}образом, если мы не установим из-за игнорированияsuccessЗначение поля может вызвать NPE, что явно не то, что мы хотим видеть.

Конечно, в программировании нет абсолютов. Два пути — это два способа мышления, и еще один способ мышления предоставляется читателям для самостоятельного выбора в ежедневном развитии.

Суммировать

В этой статье представлены тип и наименование определения переменной логического типа, и, наконец, мы можем сделать вывод, что при определении переменной логического типа, особенно при возврате значения во внешний интерфейс, мы должны использоватьsuccessНапример, в Руководстве по разработке Java для Alibaba рекомендуется использовать классы инкапсуляции для определения переменных в возвращаемых значениях POJO и RPC. Но это не значит, что null можно использовать по желанию, мы все равно должны стараться избегать иметь дело с null.

Что ж, вышесказанное касается правильного определения логических переменных в POJO. Вы использовали его правильно?

Наконец, я рекомендую «Эффективность кода», книгу, которую должны иметь все программисты, чтобы писать хороший код.

Статья в публичном аккаунте Hollis уполномочила осуществлять защиту оригинальных прав.Во избежание ненужных проблем с ответственностью за авторские права просьба указывать источник для перепечатки!

В последний месяц 2018 года у Hollis's Knowledge Planet действует ограниченная по времени скидка.Глубокое понимание параллельного программирования на Java: что такое безопасность потоков?Добро пожаловать присоединиться.

 

Столкнувшись с проблемой Java 188: в чем разница между GBK, GB2312 и GB18030?

Дорога к Богу, выпуск 015: Глубокое изучение IOP в Java

Углубленная проблема параллелизма 002: дальнейшее понимание потоков в Java (часть 1)

- ЕЩЕ | Другие интересные статьи -

Если вам нравится эта статья.

Пожалуйста, нажмите и удерживайте QR-код, чтобы подписаться на Холлис

Переадресация круга друзей - самая большая поддержка для меня.