Java Необязательно - orElse () против orElseGet ()

Необязательный Java - orElse () против orElseGet ()

1. Вступление

APIOptional обычно имеет два метода, которые могут вызвать путаницу:orElse() andorElseGet().

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

2. Подписи

Давайте сначала начнем с основ, посмотрев на их подписи:

public T orElse(T other)

public T orElseGet(Supplier other)

Понятно, чтоorElse() ставит любой параметр типаwhere, посколькуorElseGet() принимает функциональный интерфейс типаSupplier, который возвращает объект типаT.

Теперь, исходя из ихJavadocs:

  • orElse(): возвращает значение, если оно присутствует, в противном случае возвращаетother

  • orElseGet(): возвращает значение, если оно присутствует, в противном случае вызовитеother и верните результат своего вызова

3. Различия

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

3.1. orElse()с

Предполагая, что нашlogger настроен правильно, давайте начнем с написания простого фрагмента кода:

String name = Optional.of("example")
  .orElse(getRandomName());

Обратите внимание, чтоgetRandomName()  - это метод, который возвращает случайныйname  изList<String>ofnames:

public String getRandomName() {
    LOG.info("getRandomName() method - start");

    Random random = new Random();
    int index = random.nextInt(5);

    LOG.info("getRandomName() method - end");
    return names.get(index);
}

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

getRandomName() method - start
getRandomName() method - end

Переменнаяname will hold “example” завершила выполнение кода.

С его помощью легко вывести, чтоparameter of orElse() is evaluated even when having a non-empty Optional.

3.2. orElseGet()с

Теперь давайте попробуем написать аналогичный код, используяorElseGet():

String name = Optional.of("example")
  .orElseGet(() -> getRandomName());

Приведенный выше код не будет вызывать методgetRandomName() .

Помните (из документации Javadoc), что метод Supplier , переданный в качестве аргумента, выполняется только тогда, когдаan Optional value отсутствует.

Таким образом, использованиеorElseGet()  для нашего случая сэкономит нам время, затрачиваемое на вычисление случайногоname.

4. Измерение влияния на производительность

Теперь, чтобы также понять разницу в производительности, давайте воспользуемсяJMH и посмотрим некоторые реальные цифры:

@Benchmark
@BenchmarkMode(Mode.AverageTime)
public String orElseBenchmark() {
    return Optional.of("example").orElse(getRandomName());
}

ИorElseGet():

@Benchmark
@BenchmarkMode(Mode.AverageTime)
public String orElseGetBenchmark() {
    return Optional.of("example").orElseGet(() -> getRandomName());
}

Выполняя наши методы тестирования, мы получаем:

Benchmark           Mode  Cnt      Score       Error  Units
orElseBenchmark     avgt   20  60934.425 ± 15115.599  ns/op
orElseGetBenchmark  avgt   20      3.798 ±     0.030  ns/op

Как мы видим, влияние на производительность может быть значительным даже для такого простого сценария использования.

Однако приведенные выше числа могут незначительно отличаться,orElseGet() has clearly outperformed orElse() for our particular example.

В конце концов,orElse() синхронизирует вычисление методаgetRandomName()  для каждого прогона.

5. Что важно?

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

  • Что если метод выполнит некоторую дополнительную логику? E.g. делать некоторые вставки или обновления БД

  • Даже когда мы назначаем объект параметруorElse() :

    String name = Optional.of("example").orElse("Other")

    мы все еще создаем объект“Other” без причины

Вот почему для нас важно принять тщательное решение средиorElse() andorElseGet()  в зависимости от наших потребностей -by default, it makes more sense to use orElseGet() every time unless the default object is already constructed and accessible directly.

6. Заключение

В этой статье мы узнали нюансы между методамиOptional orElse() andOrElseGet() . Мы также заметили, как иногда такие простые понятия могут иметь более глубокое значение.

Как всегда, полный исходный код можно найтиover on Github.