Optional.ifPresent ()의 적절한 사용


98

Java 8 ifPresent()에서 OptionalAPI 의 방법 을 이해하려고합니다 .

나는 간단한 논리가 있습니다.

Optional<User> user=...
user.ifPresent(doSomethingWithUser(user.get()));

그러나 이로 인해 컴파일 오류가 발생합니다.

ifPresent(java.util.functionError:(186, 74) java: 'void' type not allowed here)

물론 다음과 같이 할 수 있습니다.

if(user.isPresent())
{
  doSomethingWithUser(user.get());
}

그러나 이것은 정확히 어수선한 null수표 와 같습니다 .

코드를 다음과 같이 변경하면 :

 user.ifPresent(new Consumer<User>() {
            @Override public void accept(User user) {
                doSomethingWithUser(user.get());
            }
        });

코드가 더러워 져서 예전 null수표 로 돌아 가야한다고 생각하게합니다 .

어떤 아이디어?

답변:


159

Optional<User>.ifPresent()Consumer<? super User>인수로 취합니다 . 유형이 void 인 표현식을 전달합니다. 그래서 그것은 컴파일되지 않습니다.

소비자는 람다 식으로 구현됩니다.

Optional<User> user = ...
user.ifPresent(theUser -> doSomethingWithUser(theUser));

또는 메서드 참조를 사용하면 더 간단합니다.

Optional<User> user = ...
user.ifPresent(this::doSomethingWithUser);

이것은 기본적으로

Optional<User> user = ...
user.ifPresent(new Consumer<User>() {
    @Override
    public void accept(User theUser) {
        doSomethingWithUser(theUser);
    }
});

아이디어는 doSomethingWithUser()사용자가있는 경우에만 메서드 호출이 실행된다는 것입니다. 코드는 메서드 호출을 직접 실행하고 void 결과를에 전달하려고합니다 ifPresent().


2
코드가 복잡해지고 있습니다. null 검사가 훨씬 더 깔끔해집니다. ? 당신이 doSomethingWithUser 정적 방법이 아니라고 특별히이야 생각하지 않는다
레이맨은

4
어떤 코드? 사용해야하는 것은 인스턴스 (즉, 비 정적) 메서드 doSomethingWithUser ()를 호출하는 두 번째 것입니다. 나는 그것이 어떻게 어수선한 지 보지 못합니다. 마지막 코드는 pre-lambda 세계의 lambda에 해당하는 것을 설명하기위한 것입니다. 그것을 사용하지 마십시오.
JB Nizet 2014-06-15

2
예,하지만 익명 클래스에 익숙 할 수 있으므로 익명 클래스에 해당하는 것을 확인하여 람다가 수행하는 작업을 이해할 수 있습니다. 그게 요점입니다.
JB Nizet 2014-06-15

1
수정할 것이 없습니다. 그대로두고 두 번째 예제를 사용하십시오.user.ifPresent(this::doSomethingWithUser);
JB Nizet 2014-06-15

11
@rayman 반환하는 함수가 Optional<User>있는 경우 로컬 변수에 저장할 필요가없는 경우가 많습니다. 메소드 호출을 연결하기 만하면됩니다.funcThatMightReturnUser().ifPresent(this::doSomethingWithUser);
Stuart Marks

21

@JBNizet의 답변 외에도 일반적인 사용 사례 ifPresent는 다음 .isPresent().get()같이 결합하는 것입니다 .

이전 방식 :

Optional opt = getIntOptional();
if(opt.isPresent()) {
    Integer value = opt.get();
    // do something with value
}

새로운 방식:

Optional opt = getIntOptional();
opt.ifPresent(value -> {
    // do something with value
})

이것은 나에게 더 직관적입니다.


9

간단하게 만들 수 있는데 왜 복잡한 코드를 작성합니까?

실제로 Optional클래스 를 절대적으로 사용하려는 경우 가장 간단한 코드는 이미 작성한 코드입니다.

if (user.isPresent())
{
    doSomethingWithUser(user.get());
}

이 코드는

  1. 읽을 수있는
  2. 디버그하기 쉬움 (중단 점)
  3. 까다 롭지 않다

Oracle이 OptionalJava 8에 클래스를 추가 했다고해서이 클래스가 모든 상황에서 사용되어야한다는 의미는 아닙니다.


1
ifPresent 사용의 주요 이점은 get ()을 수동으로 호출 할 필요가 없다는 것입니다. get ()을 수동으로 호출하면 isPresent를 먼저 확인하는 것을 잊기 쉽기 때문에 오류가 발생하기 쉽습니다.하지만 ifPresent를 사용하면 잊어 버리는 것은 불가능합니다
dustinroepsch

1
좋습니다. 'user'객체를 사용할 때마다 .ifPresent ()를 호출해야합니다. .ifPresent ()를 너무 많이 읽을 것이므로 코드를 빨리 읽을 수 없게됩니다!
schlebe

2
프로필 페이지 ( VB.Net , Netbeans , SqlServer , PostGresql , MySql , Linq) 의 맞춤법 오류를 수정 하려면 내 서비스를 사용할 수 있습니다 . 해당 단어 목록도 있습니다.
Peter Mortensen

7

flatMap을 사용하십시오. 값이 있으면 flatMap은 해당 값만 포함하는 순차 Stream을 반환하고, 그렇지 않으면 빈 Stream을 반환합니다. 따라서 사용할 필요가 없습니다 ifPresent(). 예:

list.stream().map(data -> data.getSomeValue).map(this::getOptinalValue).flatMap(Optional::stream).collect(Collectors.toList());

3
옵션 : 스트림 java9 필요
avmohan

7

다음과 같은 메서드 참조를 사용할 수 있습니다.

user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);

메소드 ifPresent()get Consumerobject as a paremeter and (from JavaDoc ) : "값이있는 경우 값으로 지정된 소비자를 호출합니다." 가치는 귀하의 변수 user입니다.

또는이 메서드 doSomethingWithUserUser클래스에 있고 그렇지 않은 경우 다음 static과 같은 메서드 참조를 사용할 수 있습니다.

user.ifPresent(this::doSomethingWithUser);

1
그러나 doSomethingWithUser는 정적 메서드도 아니고 클래스도 아닙니다.
레이맨

: 좋아 @rayman, 그렇지 않으면 당신이 이렇게 할 수있는 정적user.ifPresent(new ClassNameWhereMethodIs()::doSomethingWithUser);
알렉산드르 Podkutin

7
@AleksandrPodkutin 하나의 메서드를 실행하기 위해 클래스의 새 인스턴스를 만들면 안됩니다. OP에서 메서드가 호출되는 것과 동일한 클래스에있는 것처럼 들리므로 그는 사용해야합니다user.ifPresent(this::doSomethingWithUser);
Marv

@Marv 동일한 클래스에 있다는 확인 양식 OP가 표시되지 않습니다. 하지만 그런 감정이 있다면 그가 user.ifPresent(this::doSomethingWithUser);. 내 대답에 추가하겠습니다.
Aleksandr Podkutin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.