Optional<T>.orElse()
와 Optional<T>.orElseGet()
방법 의 차이점을 이해하려고 합니다.
이 orElse()
방법에 대한 설명 은 “있는 경우 값을 반환하고, 그렇지 않으면 다른 값을 반환합니다.”입니다.
그 orElseGet()
방법에 대한 설명 은 “있는 경우 값을 반환하고, 그렇지 않으면 다른 것을 호출하고 해당 호출의 결과를 반환합니다.”입니다.
이 orElseGet()
메소드는 기본적으로 매개 변수를 취하지 않고을 리턴하는 공급 업체 기능 인터페이스를 사용합니다 T
.
어떤 상황에서 사용해야 orElseGet()
합니까? 당신이 방법을 가지고 있다면 T myDefault()
왜 optional.orElse(myDefault())
오히려 하지 optional.orElseGet(() -> myDefault())
않겠습니까?
orElseGet()
람다 식의 실행을 나중에 또는 다른 것으로 연기하는 것 같지 않으므로 요점은 무엇입니까? (나는 그것이 안전한 반환 경우가 더 유용 할 것이라고 생각했을 Optional<T>
그 get()
발생하지 NoSuchElementException
및 isPresent()
항상 반환 분명 사실 …하지만이 아니, 그것은 단지 반환 T
등을orElse()
).
내가 놓친 다른 차이점이 있습니까?
답변
다음 두 가지 시나리오를 수행하십시오.
Optional<Foo> opt = ...
Foo x = opt.orElse( new Foo() );
Foo y = opt.orElseGet( Foo::new );
경우 opt
값을 포함하지 않는, 두 사람은 참으로 동일합니다. 하지만 opt
않는 값을 포함, 얼마나 많은 Foo
객체를 생성 할 것인가?
추신 : 물론이 예에서는 차이를 측정 할 수는 없지만 원격 웹 서비스 또는 데이터베이스에서 기본값을 가져와야하는 경우 갑자기 매우 중요합니다.
답변
짧은 답변:
- orElse () 는
Optional.isPresent()
값에 관계없이 원하는지 여부에 관계없이 항상 주어진 함수를 호출합니다. - orElseGet () 은 주어진 함수 만 호출 할 때
Optional.isPresent() == false
실제 코드에서 필요한 리소스 를 얻는 데 비용 이 많이 드는 경우 두 번째 방법을 고려할 수 있습니다.
// Always get heavy resource
getResource(resourceId).orElse(getHeavyResource());
// Get heavy resource when required.
getResource(resourceId).orElseGet(() -> getHeavyResource())
자세한 내용은이 함수와 함께 다음 예제를 고려하십시오.
public Optional<String> findMyPhone(int phoneId)
차이점은 다음과 같습니다.
X : buyNewExpensivePhone() called
+——————————————————————————————————————————————————————————————————+——————————————+
| Optional.isPresent() | true | false |
+——————————————————————————————————————————————————————————————————+——————————————+
| findMyPhone(int phoneId).orElse(buyNewExpensivePhone()) | X | X |
+——————————————————————————————————————————————————————————————————+——————————————+
| findMyPhone(int phoneId).orElseGet(() -> buyNewExpensivePhone()) | | X |
+——————————————————————————————————————————————————————————————————+——————————————+
때 optional.isPresent() == false
, 두 가지 방법 사이에 차이가 없습니다. 그러나, optional.isPresent() == true
, orElse()
항상 당신이 원하는 여부 후속 함수를 호출합니다.
마지막으로 사용 된 테스트 케이스는 다음과 같습니다.
결과:
------------- Scenario 1 - orElse() --------------------
1.1. Optional.isPresent() == true
Going to a very far store to buy a new expensive phone
Used phone: MyCheapPhone
1.2. Optional.isPresent() == false
Going to a very far store to buy a new expensive phone
Used phone: NewExpensivePhone
------------- Scenario 2 - orElseGet() --------------------
2.1. Optional.isPresent() == true
Used phone: MyCheapPhone
2.2. Optional.isPresent() == false
Going to a very far store to buy a new expensive phone
Used phone: NewExpensivePhone
암호:
public class TestOptional {
public Optional<String> findMyPhone(int phoneId) {
return phoneId == 10
? Optional.of("MyCheapPhone")
: Optional.empty();
}
public String buyNewExpensivePhone() {
System.out.println("\tGoing to a very far store to buy a new expensive phone");
return "NewExpensivePhone";
}
public static void main(String[] args) {
TestOptional test = new TestOptional();
String phone;
System.out.println("------------- Scenario 1 - orElse() --------------------");
System.out.println(" 1.1. Optional.isPresent() == true");
phone = test.findMyPhone(10).orElse(test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println(" 1.2. Optional.isPresent() == false");
phone = test.findMyPhone(-1).orElse(test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println("------------- Scenario 2 - orElseGet() --------------------");
System.out.println(" 2.1. Optional.isPresent() == true");
// Can be written as test::buyNewExpensivePhone
phone = test.findMyPhone(10).orElseGet(() -> test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println(" 2.2. Optional.isPresent() == false");
phone = test.findMyPhone(-1).orElseGet(() -> test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
}
}
답변
나는 문제를 위해 여기에 도달했다 쿠도 언급 한 .
나는 다른 사람들을 위해 내 경험을 공유하고 있습니다.
orElse
또는 orElseGet
질문입니다.
static String B() {
System.out.println("B()...");
return "B";
}
public static void main(final String... args) {
System.out.println(Optional.of("A").orElse(B()));
System.out.println(Optional.of("A").orElseGet(() -> B()));
}
인쇄물
B()...
A
A
orElse
선택적 값과 상호 의존적으로 B () 값을 평가합니다. 따라서 orElseGet
게으르다.
답변
조건 에서 새로운 가치를 얻기 위해 무언가를 평가하고 싶을 때 orElse
와 가장 큰 차이점을 말할 것 입니다.orElseGet
else
이 간단한 예를 고려하십시오-
// oldValue is String type field that can be NULL
String value;
if (oldValue != null) {
value = oldValue;
} else {
value = apicall().value;
}
이제 위 예제 Optional
를와 함께 사용하도록 변환 해 보겠습니다 orElse
.
// oldValue is Optional type field
String value = oldValue.orElse(apicall().value);
이제 위 예제 Optional
를와 함께 사용하도록 변환 해 보겠습니다 orElseGet
.
// oldValue is Optional type field
String value = oldValue.orElseGet(() -> apicall().value);
때 orElse
호출되면,이 apicall().value
평가 방법에 전달됩니다. 반면, orElseGet
평가 의 경우 oldValue
는 비어있는 경우에만 발생합니다 . orElseGet
게으른 평가를 허용합니다.
답변
다음 예제는 차이점을 보여 주어야합니다.
String destroyTheWorld() {
// destroy the world logic
return "successfully destroyed the world";
}
Optional<String> opt = Optional.empty();
// we're dead
opt.orElse(destroyTheWorld());
// we're safe
opt.orElseGet(() -> destroyTheWorld());
답은 문서에도 나타납니다.
public T orElseGet(Supplier<? extends T> other)
:
존재하는 경우 값을 리턴하고, 그렇지 않으면 다른 호출을 호출 하고 해당 호출 결과를 리턴하십시오.
가 Supplier
되지 않습니다 경우 호출 할 Optional
선물. 이므로,
존재하는 경우 값을, 그렇지 않으면 다른 값을 리턴하십시오.
other
문자열을 반환하는 메서드 인 경우 호출되지만 Optional
존재하는 경우 값이 반환되지 않습니다 .
답변
그 차이는 매우 미묘하며 많은주의를 기울이지 않으면 잘못된 방식으로 사용합니다.
가장 좋은 방법의 차이를 이해 orElse()
하고 orElseGet()
즉 orElse()
(가) 경우 항상 실행됩니다 Optional<T>
이다 널 (null) 또는 하지 ,하지만 orElseGet()
경우에만 실행됩니다 Optional<T>
이다 널 (null)이 .
orElse 의 사전 의미는 다음 과 같습니다 .- 존재하지 않는 부분을 실행하지만 여기서는 모순됩니다 (아래 예 참조).
Optional<String> nonEmptyOptional = Optional.of("Vishwa Ratna");
String value = nonEmptyOptional.orElse(iAmStillExecuted());
public static String iAmStillExecuted(){
System.out.println("nonEmptyOptional is not NULL,still I am being executed");
return "I got executed";
}
출력 : nonEmptyOptional이 NULL이 아니며 여전히 실행 중입니다.
Optional<String> emptyOptional = Optional.ofNullable(null);
String value = emptyOptional.orElse(iAmStillExecuted());
public static String iAmStillExecuted(){
System.out.println("emptyOptional is NULL, I am being executed, it is normal as
per dictionary");
return "I got executed";
}
출력 : emptyOptional은 NULL이며 실행 중입니다. 사전마다 정상입니다.
의 경우
orElseGet()
, 방법은 사전 의미에 따라 진행됩니다
.orElseGet()
선택 사항이 null 인 경우에만 파트가 실행됩니다
.
벤치 마크 :
+--------------------+------+-----+------------+-------------+-------+
| 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()
분명히 성능이 뛰어났습니다orElse()
.
그것은 매우 기본적인 근거를 원하는 나 같은 사람들의 의심을 없애기를 바랍니다 🙂
답변
우선 두 방법의 선언을 확인하십시오.
1) OrElse : 논리를 실행하고 결과를 인수로 전달합니다.
public T orElse(T other) {
return value != null ? value : other;
}
2) OrElseGet : 옵션 내부의 값이 null 인 경우 논리 실행
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
위 선언에 대한 설명 :
“Optional.orElse”의 인수는 선택적 (null, empty 또는 value)의 개체 값에 관계없이 항상 실행됩니다. “Optional.orElse”를 사용하는 동안 위에서 언급 한 사항을 항상 고려하십시오. 그렇지 않으면 다음 상황에서“Optional.orElse”를 사용하는 것이 매우 위험 할 수 있습니다.
위험 -1) 로깅 문제 : orElse 내부의 내용에 로그 문이 포함 된 경우 :이 경우 매번 로깅이 끝납니다.
Optional.of(getModel())
.map(x -> {
//some logic
})
.orElse(getDefaultAndLogError());
getDefaultAndLogError() {
log.error("No Data found, Returning default");
return defaultValue;
}
위험 -2) 성능 문제 : orelse 내부의 컨텐츠가 시간 집약적 인 경우 : 시간 집약적 인 컨텐츠는 모든 i / o 조작 DB 호출, API 호출, 파일 읽기가 될 수 있습니다. 이러한 내용을 orElse ()에 넣으면 시스템은 사용하지 않는 코드를 실행하게됩니다.
Optional.of(getModel())
.map(x -> //some logic)
.orElse(getDefaultFromDb());
getDefaultFromDb() {
return dataBaseServe.getDefaultValue(); //api call, db call.
}
위험 -3) 불법 상태 또는 버그 문제 : orElse 내부의 콘텐츠가 일부 객체 상태를 변경하는 경우 : Optional.map 함수 내에서 같은 장소에 다른 객체를 사용하고있을 수 있으며 이는 치명적인 버그가 될 수 있습니다.
List<Model> list = new ArrayList<>();
Optional.of(getModel())
.map(x -> {
})
.orElse(get(list));
get(List < String > list) {
log.error("No Data found, Returning default");
list.add(defaultValue);
return defaultValue;
}
그러면 orElse ()로 언제 갈 수 있습니까?
기본값이 상수 객체 enum 인 경우 orElse를 사용하는 것이 좋습니다. 위의 모든 경우 Optional.orElse () 대신 Optional.orElseGet () (선택 사항에 비어 있지 않은 값이 포함 된 경우에만 실행)을 사용할 수 있습니다. 왜?? orElse에서는 기본 결과 값을 전달하지만 orElseGet에서는 Supplier를 전달하고 Supplier의 메소드는 Optional의 값이 null 인 경우에만 실행합니다.
주요 내용은 다음과 같습니다.
- “Optional.orElse”에 로그 문이 포함되어 있으면 사용하지 마십시오.
- 시간이 많이 걸리는 논리가 포함 된 “Optional.orElse”를 사용하지 마십시오.
- “Optional.orElse”가 일부 객체 상태를 변경하는 경우 사용하지 마십시오.
- 상수 enum을 반환해야하는 경우“Optional.orElse”를 사용하십시오.
- 1, 2 및 3 포인트에서 언급 된 상황에서“Optional.orElseGet”을 선호하십시오.
나는 나의 중간 블로그 에서 point-2 ( “Optional.map/Optional.orElse”! =“if / else” ) 에서 이것을 설명했다 . 코더가 아닌 프로그래머로 Java8 사용