Java 带有无效返回类型的链选项

Java 带有无效返回类型的链选项,java,spring,Java,Spring,JDK 8: 我正在验证输入请求。有没有一种方法可以很好地连锁这些选项?或者用其他方法让它看起来更漂亮,去掉太多的可选支票?有点难看 在REST控制器类中: { ... Optional<ResponseEntity<?>> operationError = requestValidator.handleOperationError(bodyParams, myHandler, serviceInstance, null); if( operatio

JDK 8:

我正在验证输入请求。有没有一种方法可以很好地连锁这些选项?或者用其他方法让它看起来更漂亮,去掉太多的可选支票?有点难看

在REST控制器类中:

{
   ...

   Optional<ResponseEntity<?>> operationError = requestValidator.handleOperationError(bodyParams, myHandler, serviceInstance, null);
    if( operationError.isPresent()){
        return operationError.get();
    }

    Optional<ResponseEntity<?>> otherError = requestValidator.checkRequestOther(serviceInstance, bodyParams, instanceAction);
    if( otherError.isPresent()){
        return otherError.get();
    }

    Optional<ResponseEntity<?>> someWeirdError = requestValidator.checksomeWeird(serviceInstance, instanceAction);
    if( someWeirdError.isPresent()){
        return someWeirdError.get();
    }

    Optional<ResponseEntity<?>> conflictError = requestValidator.conflictExists(instanceAction,serviceInstance);
    if( conflictError.isPresent()){
        return conflictError.get();
    }

   //If All fine start doing business logic
}
是的,您可以将可选值链接到流中,但我只会在获取可选值便宜的情况下这样做,因为即使存在第一个可选值,也会对它们进行评估:

Optional<ResponseEntity<?>> operationError = 
    requestValidator.handleOperationError(bodyParams, myHandler, serviceInstance, null);
Optional<ResponseEntity<?>> otherError = 
    requestValidator.checkRequestOther(serviceInstance, bodyParams, instanceAction);
Optional<ResponseEntity<String>> some409Error = 
    requestValidator.checkSome409(serviceInstance, instanceAction);
Optional<ResponseEntity<?>> conflictError = 
    requestValidator.conflictExists(instanceAction,serviceInstance);

Optional<ResponseEntity<String>> anyError = 
    Stream.of(operationError, otherError, some409Error, conflictError)
          .filter(Optional.isPresent)
          .map(Optional::get)
          .findFirst();

if (anyError.isPresent) {
    return anyError.get();
}
一个惰性计算的Java 8解决方案:

@SafeVarargs
public static <E> Optional<E> any(final Supplier<Optional<E>>... optionalSuppliers) {
    return Stream.of(optionalSuppliers)
                 .map(Supplier::get)
                 .filter(Optional::isPresent)
                 .map(Optional::get)
                 .findFirst();
}
和callsite:

Optional<ResponseEntity<?>> anyError = any(
    () -> requestValidator.handleOperationError(bodyParams, myHandler, serviceInstance, null),
    () -> requestValidator.checkRequestOther(serviceInstance, bodyParams, instanceAction),
    () -> requestValidator.checkSome409(serviceInstance, instanceAction),
    () -> requestValidator.conflictExists(instanceAction, serviceInstance)
);

if (anyError.isPresent) {
    return anyError.get();
}
是的,您可以将可选值链接到流中,但我只会在获取可选值便宜的情况下这样做,因为即使存在第一个可选值,也会对它们进行评估:

Optional<ResponseEntity<?>> operationError = 
    requestValidator.handleOperationError(bodyParams, myHandler, serviceInstance, null);
Optional<ResponseEntity<?>> otherError = 
    requestValidator.checkRequestOther(serviceInstance, bodyParams, instanceAction);
Optional<ResponseEntity<String>> some409Error = 
    requestValidator.checkSome409(serviceInstance, instanceAction);
Optional<ResponseEntity<?>> conflictError = 
    requestValidator.conflictExists(instanceAction,serviceInstance);

Optional<ResponseEntity<String>> anyError = 
    Stream.of(operationError, otherError, some409Error, conflictError)
          .filter(Optional.isPresent)
          .map(Optional::get)
          .findFirst();

if (anyError.isPresent) {
    return anyError.get();
}
一个惰性计算的Java 8解决方案:

@SafeVarargs
public static <E> Optional<E> any(final Supplier<Optional<E>>... optionalSuppliers) {
    return Stream.of(optionalSuppliers)
                 .map(Supplier::get)
                 .filter(Optional::isPresent)
                 .map(Optional::get)
                 .findFirst();
}
和callsite:

Optional<ResponseEntity<?>> anyError = any(
    () -> requestValidator.handleOperationError(bodyParams, myHandler, serviceInstance, null),
    () -> requestValidator.checkRequestOther(serviceInstance, bodyParams, instanceAction),
    () -> requestValidator.checkSome409(serviceInstance, instanceAction),
    () -> requestValidator.conflictExists(instanceAction, serviceInstance)
);

if (anyError.isPresent) {
    return anyError.get();
}

首先,我想说:最干净的解决方案需要比可选方案更好的抽象,因为它的主要目的是表示缺少的值,而不是验证输出

但是,通过使用Optional::或自JDK 9以来添加的

Optional<ResponseEntity<?>> validationError = 
    requestValidator.handleOperationError(bodyParams, myHandler, serviceInstance, null)
    .or(() -> requestValidator.checkRequestOther(serviceInstance, bodyParams, instanceAction))
    .or(() -> requestValidator.checkSomeWeird(serviceInstance, instanceAction))
    .or(() -> requestValidator.conflictExists(instanceAction,serviceInstance));
if( validationError.isPresent() ){
    return validationError.get();
}

首先,我想说:最干净的解决方案需要比可选方案更好的抽象,因为它的主要目的是表示缺少的值,而不是验证输出

但是,通过使用Optional::或自JDK 9以来添加的

Optional<ResponseEntity<?>> validationError = 
    requestValidator.handleOperationError(bodyParams, myHandler, serviceInstance, null)
    .or(() -> requestValidator.checkRequestOther(serviceInstance, bodyParams, instanceAction))
    .or(() -> requestValidator.checkSomeWeird(serviceInstance, instanceAction))
    .or(() -> requestValidator.conflictExists(instanceAction,serviceInstance));
if( validationError.isPresent() ){
    return validationError.get();
}

如果需要严格的Java 8解决方案,可以创建一个帮助器类:

public class OptionalHelper {

    public static <T> Optional<T> findFirstPresent(Supplier<Optional<T>>... optionals) {
        return Arrays.stream(optionals)
                .map(Supplier::get)
                .filter(Optional::isPresent)
                .findFirst()
                .orElse(Optional.empty());
    }
}
然后像这样使用它:

public final class Error<T> {
    private T value;

    private Error(T value) {
        this.value = value;
    }

    public static Error withValue(T value) {
        requireNonNull(value);
        return new Error(value);
    }

    public static <T> Error<T> start() {
        return new Error(null);
    }

    public static <T> Error<T> startWith(Supplier<T> firstCheck) {
        requireNonNull(firstCheck);
        return new Error(firstCheck.get());
    }

    public Error<T> thenCheck(Supplier<Error<? extends T>> nextCheck) {
        requireNonNull(nextCheck);

        return isPresent() ? this : requireNonNull(nextCheck.get());
    }

    public boolean isPresent() {
        return value != null;
    }

    public T get() {
        return value; // I think no need to be particularly fancy here, null means "No Error"
    }
}
    Optional<ResponseEntity<?>> validationError = OptionalHelper.findFirstPresent(
            () -> requestValidator.handleOperationError(bodyParams, myHandler, serviceInstance, null),
            () -> requestValidator.checkRequestOther(serviceInstance, bodyParams, instanceAction),
            () -> requestValidator.checkSomeWeird(serviceInstance, instanceAction),
            () -> requestValidator.conflictExists(instanceAction, serviceInstance));

    if (validationError.isPresent()) {
        return validationError.get();
    }

如果需要严格的Java 8解决方案,可以创建一个帮助器类:

public class OptionalHelper {

    public static <T> Optional<T> findFirstPresent(Supplier<Optional<T>>... optionals) {
        return Arrays.stream(optionals)
                .map(Supplier::get)
                .filter(Optional::isPresent)
                .findFirst()
                .orElse(Optional.empty());
    }
}
然后像这样使用它:

public final class Error<T> {
    private T value;

    private Error(T value) {
        this.value = value;
    }

    public static Error withValue(T value) {
        requireNonNull(value);
        return new Error(value);
    }

    public static <T> Error<T> start() {
        return new Error(null);
    }

    public static <T> Error<T> startWith(Supplier<T> firstCheck) {
        requireNonNull(firstCheck);
        return new Error(firstCheck.get());
    }

    public Error<T> thenCheck(Supplier<Error<? extends T>> nextCheck) {
        requireNonNull(nextCheck);

        return isPresent() ? this : requireNonNull(nextCheck.get());
    }

    public boolean isPresent() {
        return value != null;
    }

    public T get() {
        return value; // I think no need to be particularly fancy here, null means "No Error"
    }
}
    Optional<ResponseEntity<?>> validationError = OptionalHelper.findFirstPresent(
            () -> requestValidator.handleOperationError(bodyParams, myHandler, serviceInstance, null),
            () -> requestValidator.checkRequestOther(serviceInstance, bodyParams, instanceAction),
            () -> requestValidator.checkSomeWeird(serviceInstance, instanceAction),
            () -> requestValidator.conflictExists(instanceAction, serviceInstance));

    if (validationError.isPresent()) {
        return validationError.get();
    }


也许可以使用org.springframework.validation.Error的一些实现?2件事:丑陋不是来自选项,而是来自选项周围充斥着副作用的代码。与flatMaps链接的要点是通过一系列函数调用传递一个装箱的值,其中有4个不同的东西,这不像flatMap这个@$%那么容易。“所以这不会变得很漂亮。”内森·休斯说。同意,你能展示一个比使用选项更好的设计吗?也许是一些代码示例?不,这只是说您可能需要降低期望值。现有的答案可能和它得到的一样好。也许可以使用org.springframework.validation.Error的一些实现?2件事:丑陋不是来自选项,而是来自选项周围所有副作用泛滥的代码。与flatMaps链接的要点是通过一系列函数调用传递一个装箱的值,其中有4个不同的东西,这不像flatMap这个@$%那么容易。“所以这不会变得很漂亮。”内森·休斯说。同意,你能展示一个比使用选项更好的设计吗?也许是一些代码示例?不,这只是说您可能需要降低期望值。现有的答案可能和它得到的一样好。谢谢,但这不是我的情况,我应该立即停止执行并return@Spring那么我会选择普罗霍洛夫先生的解决方案。无论如何,这是最好的。我不知道Optional::orCurious为什么即使你说findFirst?@Spring也会对它们进行计算,因为它们是在你创建Optional时进行计算的,所以在它与流有任何关系之前。要使用流进行惰性评估,您需要一个Stream@Spring请参阅我的更新答案,了解一个在Java 8中工作的惰性计算解决方案。谢谢,但这不是我的情况,我应该立即停止执行return@Spring那么我会选择普罗霍洛夫先生的解决方案。无论如何,这是最好的。我不知道Optional::orCurious为什么即使你说findFirst?@Spring也会对它们进行计算,因为它们是在你创建Optional时进行计算的,所以在它与流有任何关系之前。要使用流进行惰性评估,您需要一个Stream@Spring请参阅我的更新答案,了解一个在Java 8.thx中惰性计算和工作的解决方案。我应该提到它的JDK 8。您将如何改进这里的抽象性?@Spring,您需要一个反向可选项,该选项的单位从空值开始,并通过接受供应商将其值恰好更改一次为非空值。也可能有一个平面图,它总是首选第一个填充的对象,如果当前实例已填充,则它是一个不可操作的对象。听起来不错!不过,如果您能给我指出代码示例,那就太好了。@Spring,我添加了一个示例错误容器,它实现了我所说的内容。您的回答很有见地。在其他场合可能会有所帮助。对于我的问题,我选择了Benoit的答案,因为它是simplerthx。我应该提到它的JDK 8。您将如何改进这里的抽象性?@Spring,您需要一个反向可选项,该选项的单位从空值开始,并通过接受供应商将其值恰好更改一次为非空值。也可能有一个平面图,它总是首选第一个填充的对象,如果当前实例已填充,则它是一个不可操作的对象。听起来不错!不过,如果您能给我指出代码示例,那就太好了。@Spring,我已经添加了一个示例错误conta
你的回答很有见地。在其他场合可能会有所帮助。对于我的问题,我选择了Benoit的答案,因为它是简单的双重检查,在返回之前不会执行所有语句。正确吗?@Spring,不,这将一直执行,直到从供应商处返回第一个非空可选项为止。我在这里的另一个答案下面的评论中谈到了这个确切的appriach。您可以drom sequential call,Arrays.stream已经创建了sequential stream,非sequential streams有一个单独的parallelStream。@M.Prokhorov谢谢您提供的详细信息。答案已更新。@Spring对于错误不兼容的相等约束,我认为您必须更改checkSome409的签名才能返回Optional@Benoit在您的示例中,使用平面地图比使用地图有什么优势吗?我看到许多使用flatmap的示例。若要进行双重检查,则在返回之前不会执行所有语句。正确吗?@Spring,不,这将一直执行,直到从供应商处返回第一个非空可选项为止。我在这里的另一个答案下面的评论中谈到了这个确切的appriach。您可以drom sequential call,Arrays.stream已经创建了sequential stream,非sequential streams有一个单独的parallelStream。@M.Prokhorov谢谢您提供的详细信息。答案已更新。@Spring对于错误不兼容的相等约束,我认为您必须更改checkSome409的签名才能返回Optional@Benoit在您的示例中,使用平面地图比使用地图有什么优势吗?我看到许多使用flatmap的示例。谢谢