Перейти к основному содержимому

Необязательный илиОстальное Необязательный

· 3 мин. чтения

1. Введение

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

В этом уроке мы кратко упомянем, как мы можем это сделать — что сложнее, чем кажется.

Для ознакомления с необязательным классом Java взгляните на нашу предыдущую статью .

2. Ява 8

В Java 8 нет прямого способа вернуть другой необязательный параметр, если первый пуст.

Поэтому мы можем реализовать собственный пользовательский метод:

public static <T> Optional<T> or(Optional<T> optional, Optional<T> fallback) {
return optional.isPresent() ? optional : fallback;
}

А на практике:

@Test
public void givenOptional_whenValue_thenOptionalGeneralMethod() {
String name = "Filan Fisteku";
String missingOptional = "Name not provided";
Optional<String> optionalString = Optional.ofNullable(name);
Optional<String> fallbackOptionalString = Optional.ofNullable(missingOptional);

assertEquals(
optionalString,
Optionals.or(optionalString, fallbackOptionalString));
}

@Test
public void givenEmptyOptional_whenValue_thenOptionalGeneralMethod() {
Optional<String> optionalString = Optional.empty();
Optional<String> fallbackOptionalString = Optional.ofNullable("Name not provided");

assertEquals(
fallbackOptionalString,
Optionals.or(optionalString, fallbackOptionalString));
}

2.1. Ленивая оценка

Вышеупомянутое решение имеет один серьезный недостаток — нам нужно оценить обе необязательные переменные, прежде чем использовать наш собственный метод or() .

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

Создадим простой класс ItemsProvider :

public class ItemsProvider {
public Optional<String> getNail(){
System.out.println("Returning a nail");
return Optional.of("nail");
}

public Optional<String> getHammer(){
System.out.println("Returning a hammer");
return Optional.of("hammer");
}
}

Вот как мы можем связать эти методы и воспользоваться преимуществами ленивых вычислений :

@Test
public void givenTwoOptionalMethods_whenFirstNonEmpty_thenSecondNotEvaluated() {
ItemsProvider itemsProvider = new ItemsProvider();

Optional<String> item = itemsProvider.getNail()
.map(Optional::of)
.orElseGet(itemsProvider::getHammer);

assertEquals(Optional.of("nail"), item);
}

Приведенный выше тестовый пример печатает только «Возврат гвоздя» . Это ясно указывает на то, что был выполнен только метод getNail() .

3. Ява 9

В Java 9 добавлен метод or() , который мы можем использовать для получения Optional или другого значения, если этого Optional нет .

Давайте посмотрим это на практике на быстром примере:

public static Optional<String> getName(Optional<String> name) {
return name.or(() -> getCustomMessage());
}

Мы использовали вспомогательный метод, чтобы помочь нам с нашим примером:

private static Optional<String> getCustomMessage() {
return Optional.of("Name not provided");
}

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

@Test
public void givenOptional_whenValue_thenOptional() {
String name = "Filan Fisteku";
Optional<String> optionalString = Optional.ofNullable(name);
assertEquals(optionalString, Optionals.getName(optionalString));
}

4. Использование гуавы

Другой способ сделать это — использовать метод or() класса Optional класса guava. Во-первых, нам нужно добавить гуаву в наш проект (последнюю версию можно найти здесь ):

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>

Теперь мы можем продолжить тот же пример, что и ранее:

public static com.google.common.base.Optional<String> 
getOptionalGuavaName(com.google.common.base.Optional<String> name) {
return name.or(getCustomMessageGuava());
}
private static com.google.common.base.Optional<String> getCustomMessageGuava() {
return com.google.common.base.Optional.of("Name not provided");
}

Как мы видим, он очень похож на показанный выше. Однако он имеет небольшое отличие в названии метода и точно такой же, как метод or() класса Optional из JDK 9.

Теперь мы можем протестировать его, как в примере выше:

@Test
public void givenGuavaOptional_whenInvoke_thenOptional() {
String name = "Filan Fisteku";
Optional<String> stringOptional = Optional.of(name);

assertEquals(name, Optionals.getOptionalGuavaName(stringOptional));
}
@Test
public void givenGuavaOptional_whenNull_thenDefaultText() {
assertEquals(
com.google.common.base.Optional.of("Name not provided"),
Optionals.getOptionalGuavaName(com.google.common.base.Optional.fromNullable(null)));
}

5. Вывод

Это была краткая статья, иллюстрирующая, как добиться функциональности «Необязательный» или «Еще необязательный» .

Код для всех описанных здесь примеров и многое другое можно найти на GitHub .