무엇 이러한 두 가지 방법의 차이는 다음과 같습니다 Optional.flatMap()
과 Optional.map()
?
예를 들어 주시면 감사하겠습니다.
답변
사용 map
하는 기능은 당신이 필요로하는 개체 또는 반환하는 경우 flatMap
함수가 반환하는 경우를 Optional
. 예를 들면 다음과 같습니다.
public static void main(String[] args) {
Optional<String> s = Optional.of("input");
System.out.println(s.map(Test::getOutput));
System.out.println(s.flatMap(Test::getOutputOpt));
}
static String getOutput(String input) {
return input == null ? null : "output for " + input;
}
static Optional<String> getOutputOpt(String input) {
return input == null ? Optional.empty() : Optional.of("output for " + input);
}
두 인쇄 문 모두 같은 것을 인쇄합니다.
답변
둘 다 옵션 유형에서 무언가에 이르기까지 기능을 수행합니다.
map()
당신이 가진 옵션에 “있는 그대로 “기능을 적용합니다 :
if (optional.isEmpty()) return Optional.empty();
else return Optional.of(f(optional.get()));
함수가 함수 인 경우 어떻게됩니까 T -> Optional<U>
?
결과는 이제 Optional<Optional<U>>
!
그게 무엇 flatMap()
에 관한 것입니다 : 함수가 이미를 반환하는 경우 Optional
, flatMap()
조금 더 똑똑이며, 반환 이중 포장을하지 않습니다 Optional<U>
.
두 개의 관용구 구성 : map
및 flatten
.
답변
참고 :-아래는 맵 및 플랫 맵 기능의 예입니다. 그렇지 않은 경우 선택 사항은 기본적으로 반환 유형으로 만 사용하도록 설계되었습니다.
이미 알고 있듯이 Optional은 단일 객체를 포함하거나 포함하지 않을 수있는 일종의 컨테이너이므로 null 값을 예상하는 모든 위치에서 사용할 수 있습니다 (옵션을 올바르게 사용하면 NPE가 표시되지 않을 수 있음). 예를 들어, null을 허용 할 수있는 person 객체를 예상하는 메소드가있는 경우 다음과 같이 메소드를 작성하려고 할 수 있습니다.
void doSome(Optional<Person> person){
/*and here you want to retrieve some property phone out of person
you may write something like this:
*/
Optional<String> phone = person.map((p)->p.getPhone());
phone.ifPresent((ph)->dial(ph));
}
class Person{
private String phone;
//setter, getters
}
여기서는 선택적 유형으로 자동 래핑 된 문자열 유형을 반환했습니다.
개인 클래스가 다음과 같이 보이면 전화도 선택 사항입니다.
class Person{
private Optional<String> phone;
//setter,getter
}
이 경우 맵 함수를 호출하면 반환 된 값을 Optional에 래핑하고 다음과 같은 결과를 얻습니다.
Optional<Optional<String>>
//And you may want Optional<String> instead, here comes flatMap
void doSome(Optional<Person> person){
Optional<String> phone = person.flatMap((p)->p.getPhone());
phone.ifPresent((ph)->dial(ph));
}
추신; NullPointerExceptions 없이는 살 수 없다면 isPresent ()로 확인하지 않고 Optional에서 get 메소드 (필요한 경우)를 호출하지 마십시오.
답변
도움이 된 것은 두 함수의 소스 코드를 살펴 보는 것입니다.
맵 -결과를 선택 사항으로 묶습니다.
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value)); //<--- wraps in an optional
}
}
flatMap- ‘원시’객체를 반환
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value)); //<--- returns 'raw' object
}
}
답변
Optional.map()
:
모든 요소를 취하고 값이 존재하면 함수에 전달됩니다.
Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);
이제 추가 된 세 가지 값 중 하나가 있습니다 true
또는 false
에 랩 선택 하면, optionalValue
현재, 또는이었다 비어있는 옵션 이 없습니다.
을 사용할 수있는 결과를 처리 할 필요 ifPresent()
가없는 경우 반환 값이 없습니다.
optionalValue.ifPresent(results::add);
Optional.flatMap()
:
동일한 스트림 방법과 유사하게 작동합니다. 스트림 스트림을 평평하게합니다. 값이 표시되면 기능에 적용된다는 차이점이 있습니다. 그렇지 않으면 빈 옵션이 반환됩니다.
선택적 값 함수 호출을 작성하는 데 사용할 수 있습니다.
메소드가 있다고 가정하십시오.
public static Optional<Double> inverse(Double x) {
return x == 0 ? Optional.empty() : Optional.of(1 / x);
}
public static Optional<Double> squareRoot(Double x) {
return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x));
}
그런 다음 다음과 같이 역의 제곱근을 계산할 수 있습니다.
Optional<Double> result = inverse(-4.0).flatMap(MyMath::squareRoot);
또는 원하는 경우 :
Optional<Double> result = Optional.of(-4.0).flatMap(MyMath::inverse).flatMap(MyMath::squareRoot);
중 하나 경우 inverse()
또는 squareRoot()
반환 Optional.empty()
, 결과는 비어 있습니다.
답변
괜찮아. 당신은 당신이 중첩 된 선택적 개체에 직면 할 때 만 사용 ‘flatMap’필요 . 다음은 그 예입니다.
public class Person {
private Optional<Car> optionalCar;
public Optional<Car> getOptionalCar() {
return optionalCar;
}
}
public class Car {
private Optional<Insurance> optionalInsurance;
public Optional<Insurance> getOptionalInsurance() {
return optionalInsurance;
}
}
public class Insurance {
private String name;
public String getName() {
return name;
}
}
public class Test {
// map cannot deal with nested Optionals
public Optional<String> getCarInsuranceName(Person person) {
return person.getOptionalCar()
.map(Car::getOptionalInsurance) // ① leads to a Optional<Optional<Insurance>
.map(Insurance::getName); // ②
}
}
Stream과 마찬가지로 Optional # map은 Optional에 의해 래핑 된 값을 반환합니다. 그래서 우리는 중첩 된 Optional-을 얻습니다 Optional<Optional<Insurance>
. 그리고 ②에서, 우리는 그것을 보험 사례로 매핑하려고합니다. 그것이 비극이 일어난 방식입니다. 루트는 중첩 옵션입니다. 쉘에 관계없이 핵심 가치를 얻을 수 있다면 그것을 달성 할 수 있습니다. 이것이 flatMap이하는 일입니다.
public Optional<String> getCarInsuranceName(Person person) {
return person.getOptionalCar()
.flatMap(Car::getOptionalInsurance)
.map(Insurance::getName);
}
결국, 나는 당신이 Java8을 체계적으로 공부하고 싶다면 Java 8 In Action 을 권장합니다.