Рубрики
Без рубрики

Как заставить Вашего Рецензента Плакать, Используя Java Необязательно

Я думаю, что обзор кода – один из лучших источников вдохновения. Я рассматриваю это как возможность научиться чему-то новому… С тегом java, программирование.

Я думаю, что обзор кода – один из лучших источников вдохновения. Я рассматриваю это как возможность узнать что-то новое от других разработчиков программного обеспечения, отправляющих запросы на извлечение/слияние. Более того, иногда вам может потребоваться изучить конкретный предмет с более подробной информацией о рассматриваемом коде. Обычно этот процесс приводит к более глубокому знанию этой области. Однако есть еще один факт, касающийся проверки кода: через некоторое время вы сталкиваетесь с некоторыми распространенными ошибками. Недавно я рассмотрел функцию, в которой я увидел Необязательный подводный камень. Честно говоря, я несколько раз сталкивался с этой проблемой в разных запросах на слияние, отправленных несколькими разработчиками (от начинающих до опытных).

Я знаю, что есть тонны статей, касающихся Java Необязательно некоторые из которых весьма полезны, например этот (хотя у меня есть аргументы против некоторых случаев, упомянутых в статье) Ангела Леонарда , автора Проблемы с кодированием Java . Я не хочу повторять все содержимое, которое вы можете просто найти в Google. Я намерен рассказать о некоторых наиболее распространенных и менее решаемых подводных камнях, касающихся Необязательного использования.

Что является необязательным?

Прежде чем углубиться в основную тему, давайте рассмотрим некоторые определения и посмотрим, что Необязательно есть. Как разработчик Java, вы должны были столкнуться с печально известным исключением NullPointerException , которое возникает, когда вы собираетесь получить доступ к ссылке null . С помощью быстрого поиска вы можете найти тысячи мемов и шуток о нулевых ссылках на Java (а также на других языках). Необязательный появился в Java 8, чтобы помочь программистам избавиться от всех проблем, вызванных ссылками null . Взгляните на эту статью из технических ресурсов Oracle , чтобы узнать больше о мотивации Необязательного существования в Java.

Теперь мы собираемся взглянуть на Необязательный JavaDoc и проверить предоставленное определение.

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

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

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

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

  • Необязательным является объект-контейнер.
  • Он может не содержать ненулевого значения.
  • В основном он используется в качестве возвращаемого типа, когда использование null вызывает проблемы.
  • Переменная с необязательным типом не должна быть нулевой .

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

Старомодная Обработка Исключений

Одной из наиболее распространенных ошибок, с которыми я обычно сталкиваюсь при проверке кода, является использование блока if/else для обработки обстоятельств, при которых Необязательная переменная не содержит ненулевого значения (как ранее упоминалось в Необязательном | определение). Проверьте это:

Optional userOptional = userDao.findByCellNumber(cellNumber);

if (!userOptional.isPresent()) {
    throw new UserNotFoundException("...");
} else {
    User user = userOptional.get();
    //...
}

Предположим, что вы намереваетесь найти пользователя по определенному номеру ячейки из базы данных. Затем вы получаете Необязательную переменную из соответствующего класса DAO. Теперь вы хотите проверить, есть ли пользователь с указанным вами номером мобильного телефона. Что не так с приведенным выше кодом? Не работает? Честно говоря, это работает как заклинание. Однако это не элегантно; это что-то вроде закручивания шурупов с помощью гаечного ключа. Теперь проверьте следующий фрагмент кода:

User user = userDao.findByCellNumber(cellNumber).orElseThrow(UserNotFoundException::new);

Используя orElseThrow , вы можете сделать то же самое более лаконично и элегантно без какой-либо необходимости в методе get . Вы также можете использовать его версию без аргументов /orElseThrow , представленную в Java 10.

Злоупотребление Орельсом и Орельсегетом

Вторая распространенная ошибка может возникнуть при использовании или еще или или Еще Получить . Похоже, что эти методы делают одно и то же; однако есть существенная разница, не такая причудливая, как предыдущая. Давайте взглянем на их подписи и соответствующий Javadoc:

public T orElse(T other)
//If a value is present, returns the value, otherwise returns other.
//Parameters:
//other - the value to be returned, if no value is present. May be null.
//Returns:
//the value, if present, otherwise other
public T orElseGet(Supplier supplier)
//If a value is present, returns the value, otherwise returns the result produced by the supplying function.
//Parameters:
//supplier - the supplying function that produces a value to be returned
//Returns:
//the value, if present, otherwise the result produced by the supplying function
//Throws:
//NullPointerException - if no value is present and the supplying function is null

Что касается приведенных выше подписей, то первое различие совершенно очевидно: или же принимает универсальный объект в качестве аргумента; однако orElseGet принимает функцию поставщика, которая выдает значение. Ну и что? Вы правы; это может показаться незначительным. Однако это не так просто. Давайте проверим следующий пример:

Optional number = Optional.of(10);
System.out.println("The number is: " + number.orElseGet(() -> alternativeNumber()));

private static Integer alternativeNumber() {
    int number = 747;
    System.out.println("The alternative number is: " + number);
    return number;
}

Каков вывод приведенного выше фрагмента кода? Как вы видите, число является Необязательной переменной, инициируемой значением 10. Поэтому мы не ожидаем или же Заставить что-то сделать. Вот результат:

The number is: 10

Это очень просто, верно? А теперь проверь вот это:

Optional number = Optional.of(10);
System.out.println("The number is: " + number.orElse(alternativeNumber()));

private static Integer alternativeNumber() {
    int number = 747;
    System.out.println("The alternative number is: " + number);
    return number;
}

Все то же самое, что и в предыдущем примере, за исключением второй строки, в которой мы использовали или еще вместо Орельсегет . Мы не ожидаем, что или еще что-то сделают, потому что наш номер имеет значение. Просто остановитесь здесь и угадайте результат! Такой же, как и предыдущий? Нет! На выходе получается:

The alternative number is: 747
The number is: 10

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

Использование OrElse(нуль)

Другая распространенная ошибка, с которой я обычно сталкиваюсь в обзорах кода, в некотором роде философская; это использование OrElse(null) . Что в этом плохого? Чтобы найти ответ, давайте рассмотрим мотивацию Необязательного существования. Как я упоминал ранее, Необязательно существует, чтобы помочь вам не столкнуться с проблемами, вызванными нулевыми ссылками, такими как Исключение NullPointerException . Мы также говорили о методе OrElse в предыдущем разделе. Теперь соедините эти две части вместе. Имеет ли смысл просить наш Необязательный объект возвращать null если он пустой и не содержит значения?

Метод OrElse является правильным способом возврата альтернативного значения в случаях, когда Необязательный объект пуст. Возвращая null , ставит под сомнение использование Необязательного . Вы можете предпочесть использовать нулевую ссылку вместо Необязательно ; это нормально, хотя я никогда этого не рекомендую. Однако смешивание этих двух идей каким-то образом вводит в заблуждение. На первый взгляд код кажется нулевым безопасным; однако рано или поздно вы можете столкнуться со ссылочными проблемами null .

Возвращает значение null в методе с необязательным типом возвращаемого значения

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

public Optional findByCellNumber(String cellNumber) {
    //some code here
    if (someCondition) {
        return null;
    }
    //some code here
}

Как вы видите, этот метод возвращает null в определенном состоянии. Предположим, что база данных не работает, а автор обрабатывает исключение и возвращает null в этой ситуации ( ПЛОХАЯ ПРАКТИКА , не пытайтесь сделать это дома). Итак, есть некоторые обстоятельства, при которых вы пытаетесь получить Необязательное значение но вы сталкиваетесь с NullPointerException . Посмотри на это:

User user = userDao.findByCellNumber(cellNumber).orElseThrow(UserNotFoundException::new);

Мы ожидаем, что метод вернет Необязательный затем мы используем orElseThrow ; однако он возвращает нуль . Итак, наша попытка приводит к исключению. Как избежать этой проблемы? В этом и суть: как упоминалось ранее, Необязательный не должен быть нулевым .

Краткий обзор

  • Каждый явный вызов get метода Необязательной переменной может быть запахом кода.
  • Орельсе и orElseGet не эквивалентны.
  • Необязательный был добавлен в Java, чтобы помочь разработчикам избежать ссылок null . Таким образом, каждый возвращает нуль или Орельсе(нулевой) присутствие в вашем коде Необязательных переменных – это запах кода.

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

Оригинал: “https://dev.to/dante0747/how-to-make-your-reviewer-cry-using-java-optional-5go3”