В своей текущей работе я часто использую как потоковые, так и лямбда-выражения в Java, и ранее я написал две статьи, чтобы обобщить соответствующие знания.
- 024: Оболочка реализации потока Java: cat 1.log | grep a | sort | uniq -c | sort -rn
- Функциональное программирование заставляет забыть о шаблонах проектирования
Однако из-за дополнительной функции я не использовал ее должным образом, поэтому недавно начал читать книгу «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, личностный рост и самоуправление, а читателям предлагается опыт работы и роста передовых разработчиков. .