Java по избор - orElse () срещу orElseGet ()

1. Въведение

API на Optional обикновено има два метода, които могат да доведат до объркване: orElse () и orElseGet () .

В този бърз урок ще разгледаме разликата между тези две и ще проучим кога да използваме всеки от тях.

2. Подписи

Нека първо започнем с основите, като разгледаме техните подписи:

public T orElse(T other) public T orElseGet(Supplier other)

Ясно е, че orElse () приема всеки параметър от тип Т докато orElseGet () приема функционален интерфейс от тип доставчик , който връща обект от тип T .

Сега, въз основа на техните Javadocs:

  • orElse () : връща стойността, ако е налице, в противен случай връща други
  • orElseGet (): връща стойността, ако е налице, в противен случай извиква друго и връща резултата от неговото извикване

3. Разлики

Лесно е да бъдете малко объркани от тези опростени дефиниции, така че нека да разровим малко по-дълбоко и да разгледаме някои действителни сценарии за използване.

3.1. или друго()

Ако приемем, че нашият регистратор е конфигуриран правилно, нека започнем с писането на проста част от кода:

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

Забележете, че getRandomName () е метод, който връща произволно име от списък с имена:

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

Променливата име ще проведе "baeldung" в края на изпълнението на код.

С него можем лесно да заключим, че параметърът на orElse () се изчислява, дори когато има непразна опция .

3.2. orElseGet ()

Сега, нека опитаме да напишем подобен код с помощта на orElseGet () :

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

Горният код няма да извика метода getRandomName () .

Не забравяйте (от Javadoc), че методът на S upplier , предаден като аргумент, се изпълнява само когато не е налице незадължителна стойност.

Следователно използването на orElseGet () за нашия случай ще ни спести известно време, свързано с изчисляването на произволно име .

4. Измерване на въздействието върху ефективността

Сега, за да разберем и разликите в производителността, нека използваме JMH и да видим някои реални числа:

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

И orElseGet () :

@Benchmark @BenchmarkMode(Mode.AverageTime) public String orElseGetBenchmark() { return Optional.of("baeldung").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

Както виждаме, въздействието върху производителността може да бъде значително дори при такъв прост сценарий на използване.

Номерата по-горе може леко да се различават, но илиElseGet () очевидно е надминал orElse () за нашия конкретен пример.

Afterall или orElse () включва изчисляване на метода getRandomName () за всяко изпълнение.

5. Какво е важно?

Освен аспектите на ефективността, други фактори, които си заслужават внимание, включват:

  • Ами ако методът ще изпълни някаква допълнителна логика? Например да направите някои DB вмъквания или актуализации
  • Дори когато присвояваме обект на параметър orElse () :
    String name = Optional.of("baeldung").orElse("Other")

    все още създаваме обект „Други“ без причина

И затова е важно за нас да вземем внимателно решение между orElse () и orElseGet () в зависимост от нашите нужди - по подразбиране има по-смисъл да използваме orElseGet () всеки път, освен ако обектът по подразбиране вече не е конструиран и достъпен директно .

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

В тази статия научихме нюансите между незадължителните методи orElse () и OrElseGet () . Също така забелязахме как понякога такива прости понятия могат да имат по-дълбоко значение.

Както винаги, пълният изходен код може да бъде намерен в Github.