Java 8-Optional.flatMap과 Optional.map의 차이점


172

무엇 이러한 두 가지 방법의 차이는 다음과 같습니다 Optional.flatMap()Optional.map()?

예를 들어 주시면 감사하겠습니다.



5
@AlexisC. 귀하의 링크는 선택 사항이 아닌 Stream의지도 및 flatMap에 대한 것입니다.
Eran

1
@Eran 그것은 중요하지 않습니다. map / flatMap이 Stream 용이든 아니든 상관없이 어떻게 작동하는지 이해한다면 Optional의 경우도 동일합니다. 운영자가 스트림에서 작동하는 방식을 이해했다면이 질문을하지 않아야합니다. 개념은 동일합니다.
Alexis C.

2
@AlexisC. 별로. Optional의 flatMap은 Stream의 flatMap과 거의 공통점이 없습니다.
Eran

1
나는에 대해 말하기 해요 @Eran 개념 지도와 flatMap의 차이, 나는 사이에 일대일 대응을하고 있지 않다 Stream#flatMapOptional#flatMap.
Alexis C.

답변:


172

사용 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);
}

두 print 문은 모두 같은 것을 인쇄합니다.


5
질문 : [flat]Map매핑 함수를 input == null? 내 이해는 그것이 Optional없으면 sortcuts-[JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… )이 이것을 백업하는 것 같습니다- " 값이 있으면 적용 .. . ".
Boris the Spider

1
@BoristheSpider Optional.of (널) = Optional.empty ()!
디에고 Martinoia

14
@DiegoMartinoia Optional.of(null)Exception. Optional.ofNullable(null) == Optional.empty().
보리스 스파이더

1
@BoristheSpider 네, 맞아요. 나는 귀하의 질문에 답장하려고했지만 더 불분명하다고 생각합니다. 개념적으로 Optional.ofNullable (null)은 비어 있으면 안되지만 실제로는 것으로 간주되므로 map / flatmap이 실행되지 않습니다.
Diego Martinoia

2
나는 입력하거나 getOutputOpt 또는 getOutput에 널 (null) 일 수 없습니다 생각
DanyalBurke

61

둘 다 옵션 유형에서 무언가로 기능을 취합니다.

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>.

이 두 기능 숙어의 구성입니다 : mapflatten.


7

참고 :-아래는 map 및 flatmap 함수의 그림입니다. 그렇지 않으면 Optional은 주로 반환 유형으로 만 사용하도록 설계되었습니다.

이미 알고 있듯이 Optional은 단일 객체를 포함 할 수도 있고 포함하지 않을 수도있는 일종의 컨테이너이므로 null 값을 예상 할 때마다 사용할 수 있습니다 (Optional을 올바르게 사용하면 NPE가 표시되지 않을 수 있음). 예를 들어 nullable이 될 수있는 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
}

여기서는 Optional 유형에 자동으로 래핑되는 String 유형을 반환했습니다.

사람 클래스가 이렇다면 전화도 선택 사항입니다.

class Person{
  private Optional<String> phone;
  //setter,getter
}

이 경우 map 함수를 호출하면 반환 된 값을 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 메서드를 호출하지 마십시오 (필요한 경우).


1
이 예제는 당신의 수업 Person이 오용 하기 때문에 당신의 대답의 본질에서 산만해질 가능성이 있다고 생각합니다 Optional. Optional이와 같은 회원 에게 사용 하는 것은 API의 의도에 위배됩니다-mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…
8bitjunkie

@ 8bitjunkie 감사는 아웃 지적를 들어, 스칼라의 옵션과 다른 ..
SandeepGodara

6

저에게 도움이 된 것은 두 기능의 소스 코드를 살펴 보는 것이 었습니다.

-결과를 옵션으로 래핑합니다.

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
    }
}

2
flatMap" '원시'개체를 반환한다"는 의미는 무엇입니까 ? flatMap또한에서 "래핑 된"매핑 된 개체를 반환합니다 Optional. 차이점은의 경우이다 flatMap, 매퍼 함수에 매핑 된 객체를 포함 Optional하면서 map자체의 객체를 포함 Optional.
Derek Mahar

@DerekMahar가 내 댓글을 삭제 했으므로 다시 게시 할 필요가 없습니다. 댓글을 바로 수정했기 때문입니다.
maxxyme 2010

3
  • Optional.map():

모든 요소를 ​​취하고 값이 존재하면 함수에 전달됩니다.

Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);

이제 추가 된 값은 세 가지 값 중 하나입니다. true또는 존재하는 경우 Optional로 , 그렇지 않으면 빈 Optionalfalse 로 래핑됩니다 .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(), 결과는 비어 있습니다.


1
이것은 컴파일되지 않습니다. 두 식 모두 결과를 할당 할 Double 대신 Optional <Double>을 반환합니다.
JL_SO

@JL_SO 당신이 맞습니다. 역에는 Optional<Double>반환 유형으로 유형 이 있기 때문 입니다.
catch23

3

괜찮아. 당신은 당신이 중첩 된 선택적 개체에 직면 할 때 만 사용 '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 을 추천했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.