[java] Java에서 선택 사항 또는 기타 선택 사항

Java 8 의 새로운 Optional 유형 으로 작업하고 있으며 기능적으로 지원되지 않는 일반적인 작업 인 “orElseOptional”과 같은 기능을 살펴 보았습니다.

다음 패턴을 고려하십시오.

Optional<Result> resultFromServiceA = serviceA(args);
if (resultFromServiceA.isPresent) return result;
else {
    Optional<Result> resultFromServiceB = serviceB(args);
    if (resultFromServiceB.isPresent) return resultFromServiceB;
    else return serviceC(args);
}

이 패턴에는 여러 형태가 있지만, 현재 옵션이 존재하지 않는 경우에만 호출되는 새로운 옵션을 생성하는 함수를 취하는 옵션에 대해 “orElse”를 원합니다.

구현은 다음과 같습니다.

public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
    return value != null ? this : other.get();
}

의도하지 않은 방식으로 Optional을 사용하는 경우와 같은 방법이 존재하지 않는 이유가 있는지, 사람들 이이 사건을 처리하기 위해 다른 방법을 생각해 낸 경우 궁금합니다.

내 코드로 작업하는 사람들이 반드시 존재한다는 것을 알지 못하기 때문에 사용자 정의 유틸리티 클래스 / 메소드와 관련된 솔루션은 우아하지 않다고 생각해야합니다.

또한 누구나 아는 경우 그러한 방법이 JDK 9에 포함됩니까? 어떻게 그러한 방법을 제안 할 수 있습니까? 이것은 나에게 API에 대한 눈부신 누락처럼 보입니다.



답변

이 형태의 JDK (9)의 일부입니다 or걸립니다 Supplier<Optional<T>>. 그러면 귀하의 예는 다음과 같습니다.

return serviceA(args)
    .or(() -> serviceB(args))
    .or(() -> serviceC(args));

자세한 내용은 내가 작성한 Javadoc 또는 이 게시물을 참조하십시오 .


답변

현재 API를 고려한 가장 깨끗한 “시도 서비스”접근 방식은 다음과 같습니다.

Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
    ()->serviceA(args),
    ()->serviceB(args),
    ()->serviceC(args),
    ()->serviceD(args))
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();

중요한 측면은 한 번 작성해야하는 (일정한) 작업 체인이 아니라 다른 서비스를 추가하는 것이 얼마나 쉬운 지 (또는 서비스 목록을 수정하는 것이 일반적 임)입니다. 여기에서 싱글을 추가하거나 제거하는 ()->serviceX(args)것으로 충분합니다.

스트림의 지연 평가로 인해 선행 서비스가 비어 있지 않은 것을 리턴하면 서비스가 호출되지 않습니다 Optional.


답변

예쁘지는 않지만 작동합니다.

return serviceA(args)
  .map(Optional::of).orElseGet(() -> serviceB(args))
  .map(Optional::of).orElseGet(() -> serviceC(args))
  .map(Optional::of).orElseGet(() -> serviceD(args));

.map(func).orElseGet(sup)와 함께 사용하기에 매우 편리한 패턴입니다 Optional. “이것이 Optional가치를 포함 한다면 v, 나에게 func(v), 그렇지 않으면 나에게주세요 sup.get()“를 의미합니다.

이 경우에 우리는를 호출하고을 serviceA(args)얻는다 Optional<Result>. Optional값 이 포함되어 있으면 vget Optional.of(v)을 원하지만 비어 있으면 얻을 수 serviceB(args)있습니다. 더 많은 대안으로 헹구십시오.

이 패턴의 다른 용도는

  • .map(Stream::of).orElseGet(Stream::empty)
  • .map(Collections::singleton).orElseGet(Collections::emptySet)

답변

아마도 이것은 당신이 추구하는 것입니다 : 하나의 옵션 또는 다른 옵션에서 가치 얻기

그렇지 않으면를 살펴볼 수 있습니다 Optional.orElseGet. 다음은 내가 생각 하는 것의 예입니다 .

result = Optional.ofNullable(serviceA().orElseGet(
                                 () -> serviceB().orElseGet(
                                     () -> serviceC().orElse(null))));


답변

여전히 JDK8을 사용한다고 가정하면 몇 가지 옵션이 있습니다.

옵션 # 1 : 나만의 도우미 방법 만들기

예 :

public class Optionals {
    static <T> Optional<T> or(Supplier<Optional<T>>... optionals) {
        return Arrays.stream(optionals)
                .map(Supplier::get)
                .filter(Optional::isPresent)
                .findFirst()
                .orElseGet(Optional::empty);
    }
}

당신이 할 수 있도록 :

return Optionals.or(
   ()-> serviceA(args),
   ()-> serviceB(args),
   ()-> serviceC(args),
   ()-> serviceD(args)
);

옵션 # 2 : 라이브러리 사용

예를 들어 google guava의 Optional은 올바른 or()작업 (JDK9와 동일)을 지원합니다. 예 :

return serviceA(args)
  .or(() -> serviceB(args))
  .or(() -> serviceC(args))
  .or(() -> serviceD(args));

(각 서비스가 com.google.common.base.Optional대신을 반환 하는 위치 java.util.Optional).


답변

이것은 패턴 일치에 적합하고 Somes 및 None 구현 (예 : Javaslang , FunctionalJava ) 또는 cyclops-react 의 게으른 Maybe 구현을 사용 하는보다 전통적인 옵션 인터페이스에 적합 합니다.이 라이브러리의 저자입니다.

함께 외눈 박이-반응 당신은 또한 구조 사용할 수있는 패턴 매칭을 JDK 유형에. 옵션의 경우 방문자 패턴을 통해 현재 및 부재 한 경우에 일치시킬 수 있습니다 . 다음과 같이 보일 것입니다-

  import static com.aol.cyclops.Matchables.optional;

  optional(serviceA(args)).visit(some -> some ,
                                 () -> optional(serviceB(args)).visit(some -> some,
                                                                      () -> serviceC(args)));


답변