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));
답변
현재 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
값 이 포함되어 있으면 v
get 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)));