Одним из наиболее распространенных исключений, с которыми сталкиваются программисты Java, являются NullPointerExceptions . Это исключение выдается JVM во время выполнения как исключение времени выполнения.
Как все мы знаем, исключение NullPointerException возникает, когда приложению требуется объект, но оно нашло нулевое значение. Случаи с нулевым значением являются одним из наиболее распространенных исключений, пропущенных программистами Java.
Вам также может понравиться:
26 причин, по которым правильное использование необязательно не является обязательным
Нулевые значения необходимо обработать в приложении, прежде чем переходить к обычной бизнес-логике, чтобы избежать этого исключения во время выполнения. Это приводит к ненужным нулевым проверкам.
Чтобы иметь дело с таким типом шаблонного кода для нулевых значений в Java, в Java 8 был введен новый тип Optional <T> .
В чем проблема без Java 8 Необязательно?
Согласно Oracle, Java 8 Optional работает как тип контейнера для значения, которое, вероятно, отсутствует или равно нулю. Java Optional — последний класс, присутствующий в пакете java.util.
Давайте проверим проблему без Java 8 Необязательно.
Предположим, у нас есть следующий метод в нашем приложении. Этот метод извлекает сведения о сотруднике из базы данных и возвращает их для соответствующего идентификатора :
Джава
x
1
Employee findEmployee(String id) {
2
...
3
};
Предположим, что указанный идентификатор отсутствует в базе данных. Затем метод вернет нулевое значение. Теперь, если у нас есть код, написанный ниже:
Джава
x
1
Employee employee = findEmployee("1234");
2
System.out.println("Employee's Name = " + employee.getName());
Приведенный выше код вызовет исключение NullPointerException во время выполнения, поскольку программист не проверил значение NULL перед его использованием.
Как Java 8 Optionals обеспечивают решение?
Теперь давайте посмотрим, как Java 8 Optional решит вышеуказанную проблему и поможет в устранении NullPointerException
.
Ниже приведена модификация, необходимая для вышеуказанного кода:
Джава
x
1
Optional < Employee > findEmployee(String id) {
2
...
3
};
В приведенном выше коде мы указываем клиенту, возвращая Optional <Employee>, что существует вероятность того, что сотрудник может не существовать с данным идентификатором.
Теперь в клиентском приложении этот факт должен быть явно указан.
Клиент должен быть написан следующим образом:
Джава
x
1
Optional < Employee > optional = findEmployee("1234");
2
optional.ifPresent(employee -> {
3
System.out.println("Employee name is " + employee.getName());
4
})
Вы можете видеть, что мы создали один необязательный объект в первой строке кода выше. Теперь нам разрешено использовать различные служебные методы с объектом Optional.
Метод ifPresent()
в приведенном выше фрагменте кода вызывает предоставленное лямбда-выражение, только если сотрудник присутствует ; в противном случае это не так.
Преимущества Java 8 Необязательно
Ниже приведены некоторые из перечисленных преимуществ использования Java 8 Optional:
- NullPointerException предотвращается во время выполнения.
- Проверка нулевого значения не требуется в приложении.
- Код Boilerplate не требуется.
- Легко разрабатывать чистые и аккуратные API.
Дополнительные методы класса Java 8
методы | Описание |
---|---|
public static <T> Необязательный <T> empty () | Этот метод возвращает пустой необязательный объект. Нет значения для этого необязательного. |
public static <T> Необязательный <T> of (значение T) | Этот метод возвращает Optional с указанным значением, которое не является нулевым. |
public static <T> Необязательный <T> ofNullable (значение T) | Этот метод возвращает Необязательный, описывающий указанное значение, если значение не является нулевым; в противном случае возвращается пустое значение. |
public T get () | Если значение присутствует в этом Дополнительном, тогда это возвращает значение. В противном случае он генерирует исключение NoSuchElementException. |
public boolean isPresent () | Этот метод возвращает истинное значение, если присутствует значение. В противном случае возвращается false. |
public void ifPresent (Потребитель <? super T> потребитель) | Если значение присутствует, то вызывается потребитель с предоставленным значением. В противном случае это ничего не делает. |
public Необязательный фильтр <T> (предикат <? super T> предикат) | Если значение присутствует, и оно также соответствует данному предикату, тогда он возвращает Необязательный, описывающий значение. В противном случае он возвращает пустую опцию. |
public <U> Необязательный <U> map (Функция <? super T, extends U> mapper) | Если значение присутствует, тогда применяется функция отображения, и если результат не является нулевым значением, то он возвращает Необязательный параметр, описывающий результат. В противном случае он возвращает пустую опцию. |
public <U> Необязательный <U> flatMap (Функция <? super T, Необязательный <U> маппер) | Если значение присутствует, то оно применяет к нему предоставленную функцию сопоставления Optional-Bear и возвращает этот результат. В противном случае он возвращает пустую опцию. |
общедоступное или другое (другое) | Этот метод возвращает значение, если оно присутствует; в противном случае он возвращает другое. |
public T orElseGet (Поставщик <? extends T> прочее) | Этот метод возвращает значение, если оно присутствует. В противном случае он вызывает other и возвращает результат вызова. |
public <X extends Throwable> T orElseThrow (Поставщик <? extends X> exceptionSupplier) выбрасывает X extends Throwable | Если значение присутствует, этот метод возвращает содержащееся в нем значение. В противном случае он создает исключение, которое будет создано предоставленным поставщиком. |
public boolean equals (Object obj) | Этот метод используется для указания того, является ли какой-либо другой объект «равным» этому Дополнительному или нет. |
public int hashCode () | Этот метод возвращает значение хеш-кода текущего значения, если оно существует. В противном случае возвращается 0 (ноль). |
public String toString () | Этот метод просто используется для возврата непустого строкового представления Optional, которое подходит для отладки. |
Создание необязательного объекта Java 8
В этом разделе мы рассмотрим различные способы создания необязательного объекта Java 8:
1. Создайте пустой необязательный объект
В приведенном ниже коде показано, как создать необязательный объект со значением NULL. Это просто описывает отсутствие значения.
Джава
x
1
Optional < Employee > employee = Optional.empty();
2. Создайте необязательный объект с ненулевым значением
В приведенном ниже коде показано, как создать необязательный объект со значением, отличным от NULL.
Джава
x
1
Employee employee = new Employee("1234", "TechBlogStation");
2
Optional < Employee > optional = Optional.of(employee);
Важно отметить, что если в аргументе аргумента указано значение null Optional.of()
, оно немедленно выдаст исключение NullPointerException и не позволит вам создать объект Optional.
3. Создайте необязательный объект со значением, которое может быть как нулевым, так и ненулевым
Приведенный ниже код показывает, как создать необязательный объект, который может иметь как нулевые, так и ненулевые значения.
Джава
x
1
Optional < Employee > optional = Optional.ofNullable(employee);
Если передано ненулевое значение Optional.ofNullable()
, он вернет Необязательное, содержащее указанное значение. В противном случае он просто возвращает пустое значение Optional.
Проверка наличия значения в дополнительном объекте Java 8
Теперь давайте изучим различные способы проверки наличия значения в дополнительном объекте Java 8 с помощью различных методов:
1. isPresent()
метод
Метод isPresent()
возвращает значение true в случае, если идентификатор дополнительных объектов содержит ненулевое значение. В противном случае он возвращает ложное значение.
Джава
x
1
if (optional.isPresent()) { // Suppose the non null value is present in Optional System.out.println("Value - " + optional.get()); } else { // Suppose the null value is present in Optional System.out.println("Optional is empty"); }
2. ifPresent()
метод
В методе ifPresent()
мы передаем функцию потребителя . Эта функция Consumer будет выполняться только в том случае, если в дополнительном объекте присутствует значение.
Если Optional пуст, то он ничего не делает:
Джава
x
1
optional.ifPresent(value -> {
2
System.out.println("Value present - " + value);
3
});
В приведенном выше коде мы указали лямбда-функцию в качестве параметра ifPresent()
метода.
Получение значения из дополнительного объекта Java 8 с помощью метода get ()
get()
Метод Опционен просто используется для возврата значения из факультативного объекта. Предположим, что значение отсутствует, тогда оно генерирует исключение NoSuchElementException .
Джава
xxxxxxxxxx
1
Employee employee = optional.get()
В случае отсутствия значения выдается исключение, поэтому перед использованием get()
метода рекомендуется сначала проверить, присутствует это значение или нет.
Возврат значения по умолчанию из дополнительного объекта Java 8 с помощью метода orElse ()
Этот метод orElse()
используется для возврата значения по умолчанию, если необязательный объект пуст.
Смотрите пример ниже:
Джава
xxxxxxxxxx
1
// Below will return "Unknown Employee" if employee is null User finalEmployee = (employee != null) ? employee : new Employee("0", "Unknown Employee");
Теперь напишите приведенную выше логику, используя orElse()
метод Java 8 Optional :
Джава
xxxxxxxxxx
1
// Below will return "Unknown Employee" if employee is null User finalEmployee = optional.orElse(new Employee("0", "Unknown Employee"));
Возврат значения по умолчанию из дополнительного объекта Java 8 с помощью метода orElseGet ()
Как мы узнали, метод orElse()
возвращает одно значение по умолчанию непосредственно в случае, если необязательный объект пуст, но orElseGet()
метод принимает поставщика, и этот поставщик вызывается, когда необязательный объект пуст.
Результат, возвращаемый Поставщиком, становится значением по умолчанию для Необязательного.
Джава
x
1
User finalEmployee = optional.orElseGet(() -> {
2
return new Employee("0", "Unknown Employee");
3
});
Создайте исключение, если значение отсутствует в Java 8 Необязательно
orElseThrow()
Метод используется для метания исключения , если необязательный объект пуст.
Его можно использовать в сценарии, где объект для указанного параметра запроса не существует в REST API. Вы можете использовать этот метод для создания пользовательских исключений, таких как ResourceNotFound()
, и т.д .:
Джава
x
1
"/employees/{id}") (
2
public User getEmployee( ("id") String id) {
3
return employeeRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Employee not found with id " + id););
4
}
Фильтруйте значения, используя метод Filter () Необязательно
Предположим, у вас есть Необязательный объект Сотрудника. Теперь вы проверяете пол сотрудника и соответственно вызываете функцию.
Ниже приведен старый подход для этого:
Джава
x
1
if(employee != null && employee.getGender().equalsIgnoreCase("MALE")) { // calling the function }
Теперь давайте посмотрим, как мы можем использовать дополнительный фильтр для достижения этой цели:
Джава
x
1
optional.filter(user -> employee.getGender().equalsIgnoreCase("MALE")) .ifPresent(() -> { // Your function })
filter()
Метод принимает предикат в качестве параметра. Если необязательный параметр содержит ненулевое значение и значение соответствует указанному предикату, этот метод возвращает необязательный параметр, содержащий это значение.
В противном случае этот метод возвращает пустой Optional.
Извлечение и преобразование значений с помощью map ()
Предположим, у нас есть сценарий, в котором мы хотим извлечь адрес сотрудника, а также распечатать его местоположение в зависимости от указанного условия.
Рассмотрим приведенный ниже пример:
У нас есть getAddress()
метод в нашем Employee
классе:
Джава
x
1
Address getAddress() {
2
return this.address;
3
}
Ниже приведен типичный подход для достижения запрошенного сценария:
Джава
x
1
if (employee != null) {
2
Address address = employee.getAddress();
3
if (address != null && address.getCountry().equalsIgnoreCase("USA")) {
4
System.out.println("Employee belongs to USA");
5
}
6
}
Теперь посмотрим, как мы можем использовать map()
метод Optional для достижения тех же результатов:
Джава
x
1
userOptional.map(Employee::getAddress).filter(address -> address.getCountry().equalsIgnoreCase("USA")).ifPresent(() -> {
2
System.out.println("Employee belongs to USA");
3
});
Приведенный выше код, по сравнению с предыдущим подходом, хорошо читается, сжат и эффективен.
Давайте разберемся в коде более подробно:
Джава
xxxxxxxxxx
1
// Extracting the Employee address using map() method. Optional<Address> addressOptional = employeeOptional.map(Employee::getAddress)
2
// filtering the address from USA Optional<Address> usaAddressOptional = addressOptional.filter(address -> address.getCountry().equalsIgnoreCase("USA"));
3
// Printing if country is USA usaAddressOptional.ifPresent(() -> { System.out.println("Employee belongs to USA"); });
В приведенных выше фрагментах кода метод map()
возвращает пустой Optional в одном из следующих случаев:
- Если работника нет в
employeeOptional
. - Если сотрудник присутствует, но метод
getAddress()
возвращает ноль.
В противном случае он просто возвращает необязательный <Address>, который содержит адрес сотрудника.
Каскадные опционы с использованием flatMap ()
Теперь давайте снова рассмотрим приведенный выше пример, связанный с методом map ().
Вы можете видеть, даже если адрес Сотрудника может быть нулевым, то почему мы не возвращаем Необязательный <Address> вместо простого Address, извлеченного с помощью getAddress()
метода.
Это будет неверно, так как у нас будет проблема в следующей строке кода, если мы вернем Необязательный <Address> :
Джава
x
1
Optional<Address> addressOptional = employeeOptional.map(Employee::getAddress)
Теперь метод getAddress()
возвращается Optional<Address>
, поэтому тип возвращаемого значения employeeOptional.map()
будет Optional<Optional<Address>>
.
Это дополнительно продемонстрировано ниже:
Джава
xxxxxxxxxx
1
Optional<Optional<Address>> addressOptional = employeeOptional.map(Employee::getAddress)
Теперь мы вложили Optional, и мы не хотим этого, поэтому теперь мы можем использовать flatMap()
метод для решения этой проблемы:
Джава
xxxxxxxxxx
1
Optional<Address> addressOptional = employeeOptional.flatMap(Employee::getAddress)
Обратите внимание, что если ваша функция отображения возвращает Optional, используйте
flatMap()
inst ead of,map()
чтобы получить плоский результат от вашего Optional объекта.
Заключение
Мы узнали, что такое Java 8 Optional, его преимущества и проблемы, решаемые с помощью Optional в Java. Кроме того, мы смогли лучше понять различные методы Java 8 Optional, посмотрев на несколько иллюстративных примеров.
Спасибо за прочтение!
Дальнейшее чтение
Дополнительное использование и лучшие практики Java 8
26 причин, почему использование опционально правильно не является опцией