Избавьтесь от пыток NPE с опцией

Java

architectural-architectural-design-architecture

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

Однако из-за дополнительной функции я не использовал ее должным образом, поэтому недавно начал читать книгу «Java 8 Практический бой».Эта статья является кратким изложением уроков для главы 10.

задний план

В Java, если вы попытаетесь вызвать функцию с нулевым значением, будет выброшено NullPointerException (NPE).NPE является наиболее типичным исключением при разработке программ на Java.Для Java-разработчиков, независимо от того, являетесь ли вы новичком или работаете много лет водителей, NPE часто заставляет их переворачиваться. Чтобы избежать NPE, они добавляют много операторов if, что делает код менее читаемым.

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

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

Введение необязательного

Разработчики Java черпали вдохновение в Haskell и Scala, чтобы представить новый класс в Java 8.java.util.Optional<T>. Если интерфейс возвращает значение Optional, это может означать, что у человека может быть или не быть автомобиля. Это более явно, чем просто возврат автомобиля. Людям, читающим код, не нужно заранее готовить бизнес-знания.

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

Использование необязательного

метод описывать
empty Возвращает пустой необязательный экземпляр
filter Возвращает необязательный объект, содержащий значение, если значение существует и удовлетворяет предоставленным условиям фильтра; в противном случае возвращает пустой необязательный объект.
map Если значение существует, выполните предоставленный вызов функции сопоставления для этого значения.
flatMap Выполняет предоставленный вызов функции сопоставления для значения, если оно существует, возвращая значение типа Необязательный, в противном случае возвращает пустой необязательный объект.
ifPresent Если значение существует, выполните вызов метода, используя значение, в противном случае ничего не делайте.
of Возвращает после обертывания указанного значения с необязательным, если значение равно нулю, выдает NPE
ofNullable Возвращает указанное значение после его инкапсуляции с помощью Необязательный. Если значение равно null, возвращает пустой необязательный объект.
orElse Возвращает, если есть значение, в противном случае возвращает значение по умолчанию
orElseGet Возвращает, если есть значение, в противном случае возвращает значение, сгенерированное указанным интерфейсом Supplier (если стоимость генерации значения по умолчанию относительно высока, подходит метод orElseGet)
orElseThrow Возвращает, если есть значение, в противном случае возвращает исключение, созданное указанным интерфейсом Поставщика.
get Возвращает значение, если оно существует, в противном случае генерирует исключение NoSuchElementException.
isPresent Возвращает true, если значение существует, иначе возвращает false

В приведенной выше таблице перечислены основные API опционального, а также несколько советов по использованию:

  • Вы можете использовать ofNullable для инкапсуляции возможно нулевого объекта в качестве дополнительного объекта, а затем использовать метод orElse для предоставления значения по умолчанию при получении значения; вы можете использовать пустой метод для создания пустого дополнительного объекта; метод of обычно не используется, но если вы знаете, что определенное значение не может быть нулевым, вы можете инкапсулировать значение с помощью опционального, чтобы оно выдавало исключение, если оно равно нулю.
//empty方法的使用
Optional<Car> optCar = Optional.empty();

//of方法的使用
Optional<Car> optCar = Optional.of(car);

//ofNullable方法的使用
Optional<Car> optCar = Optional.ofNullable(car);
  • Вы можете использовать метод карты, чтобы получить значение поля из значения, которое оно инкапсулирует в объекте Optional;
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName); 
  • Если вам нужно непрерывно и постепенно получать значение поля из конца цепочки объектов, вы не можете использовать метод карты все, вам нужно сначала использовать flatMap, а затем использовать метод карты в последнюю очередь;
//转换之前
public String getCarInsuranceName(Person person) {
  return person.getCar().getInsurance().getName();
}

//转换后
public String getCarInsuranceName(Optional<Person> person) {
  return person.flatMap(Person::getCar)
               .flatMap(Car::Insurance)
               .map(Insurance::getName)
               .orElse("Unknown");
}
  • Методы map, flatMap и filter в Option аналогичны по концепции соответствующим методам в Stream, разница в том, что в Optional есть не более одного элемента, который является частным случаем Stream — особой коллекцией.
  • Не используйте методы ifPresent и get, они, по сути, являются тем же шаблоном, что и до объекта Optional, все они являются раздутыми операторами суждения if-then-else;
  • Так как необязательный не может быть сериализован, невозможно определить поле как необязательный в модели предметной области. Причина в том, что первоначальный дизайн необязательный предназначен только для поддержки синтаксиса, который может возвращать необязательные объекты. модель домена, вы можете использовать следующий альтернативный метод:
public class Person {
  private Car car;
  public Optional<Car> getCarAsOptional() {
    return Optional.ofNullable(car);
  }
}
  • Не используйте необязательный объект базового типа, причина в том, что необязательный объект базового типа не поддерживает методы map, flatMap и filter, и эти методы являются очень мощными методами в необязательном.

Практический случай

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

Методы Java могут обрабатывать аномальные результаты двумя способами: возвращать значение null (или код ошибки) и выдавать исключение, например: Integer.parseInt(String) этот метод — если соответствующее целое число не может быть проанализировано, метод выдает исключение NumberFormationException. , в этом случае мы обычно используем операторы try/catch для обработки исключений.

Как правило, мы рекомендуем отдельно извлекать блок try/catch в метод, а для разработки этого метода здесь использовать Optional Код выглядит следующим образом. В процессе разработки вы можете попытаться создать класс инструментов OptionalUtility для инкапсуляции этой сложной логики try/catch.

public static Optional<Integer> stringToInt(String a) {
  try{
    return Optional.of(Integer.parseInt(s));
  } catch  (NumberFormationException e) {
    return Optional.empty();
  }
}

Кейс 2: Комплексный кейс

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

   public static int readDuration(Properties properties, String name) {
        String value = properties.getProperty(name);
        if (value != null) {
            try {
                int i = Integer.parseInt(value);
                if (i > 0) {
                    return i;
                }
            } catch (NumberFormatException e) {

            }
        }
        return 0;
    }

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

    public static int readDurationWithOptional(Properties properties, String name) {
        return Optional.ofNullable(properties.getProperty(name))
            .flatMap(OptionalUtility::stringToInt)
            .filter(integer -> integer > 0)
            .orElse(0);
    }

Если значение свойства, к которому нужно получить доступ, не существует, возвращаемое значение метода Properites.getProperty(String) равно null, и можно использовать фабричный метод noNullable для преобразования значения в необязательный объект, после чего можно использовать flatMap чтобы преобразовать необязательный объект в необязательный; Наконец, используйте фильтр, чтобы отфильтровать отрицательные числа, а затем вы можете использовать orElse, чтобы получить значение атрибута. Если вы не можете его получить, верните значение по умолчанию, равное 0.

Суммировать

Идея использования Optional такая же, как и у Stream. Это цепная идея. Она похожа на запрос к базе данных. Она очень выразительна и избавляет от сложных методов try/catch и if-then-else. В более поздних разработках вы можете использовать Optional для разработки API, чтобы можно было разрабатывать более безопасные интерфейсы и методы.


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

javaadu