具有Java 8 lambda和可选

时间:2018-12-10 21:34:39

标签: java java-8

我不明白为什么以下代码无法编译:

private ResponseEntity<JSendResponse> buildResponse(RequestModel requestModel,
                                                    RequestModelParamConverter paramConverter,
                                                    Supplier<String> xsdSupplier,
                                                    Supplier<String> xmlTemplateSupplier) {

    return Optional.ofNullable(new RequestErrorHandler<>().validate(validator, requestModel))
            .map(validationErrors -> new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST))
            .orElse(this.buildResponseForValidRequest(requestModel, paramConverter, xsdSupplier, xmlTemplateSupplier));
}

编译错误:

  

或其他   (org.springframework.http.ResponseEntity )   不能应用于   (org.springframework.http.ResponseEntity

虽然此代码(在逻辑上我认为是相同的代码)确实可以编译:

private ResponseEntity<JSendResponse> buildResponse(RequestModel requestModel,
                                                    RequestModelParamConverter paramConverter,
                                                    Supplier<String> xsdSupplier,
                                                    Supplier<String> xmlTemplateSupplier) {

    JSendResponse validationErrors = new RequestErrorHandler<>().validate(validator, requestModel);

    if(validationErrors == null) {
        return this.buildResponseForValidRequest(requestModel, paramConverter, xsdSupplier, xmlTemplateSupplier);
    }
    else
    {
        return new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST);
    }
}

问题似乎是,如果验证失败,则RequestErrorHandler <>()。validate方法将返回一个名为JSendFailResponse的类。 JSendFailResponse是JSendResponse的子类,最终返回该子类。似乎lambda代码无法理解JSendFailResponse是JSendResponse。

如果将validationErrors强制转换为地图lambda中的JSendResponse,则可以编译它,但是随后我丢失了JSendFailResponse上的某些字段。

编辑:此代码也无法编译:

private ResponseEntity<? extends JSendResponse> buildResponse(RequestModel requestModel,
                                                    RequestModelParamConverter paramConverter,
                                                    Supplier<String> xsdSupplier,
                                                    Supplier<String> xmlTemplateSupplier) {

    return Optional.ofNullable(new RequestErrorHandler<>().validate(validator, requestModel))
            .map(validationErrors -> new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST))
            .orElse(this.buildResponseForValidRequest(requestModel, paramConverter, xsdSupplier, xmlTemplateSupplier));
}

EDIT2:这是一个简化的示例,您可以将其复制/粘贴到IDE中以亲自查看。

import java.util.*;

public class GemLamDemo {

    public static void main(String... args) {

        GemLamDemo gld = new GemLamDemo();

        gld.getList(null);

    }

    public List<? extends TypeA> getList(TypeA ta) {

        return Optional.ofNullable(ta)
                .map(a -> new ArrayList<TypeA>(Arrays.asList(a)))
                .orElse(new ArrayList<TypeB>(Arrays.asList(new TypeB())));
    }

    public class TypeA {

    }

    public class TypeB extends TypeA {

    }
}

EDIT3:我想基于到目前为止所获得的帮助,我已经理解了这个问题,但是以下代码可以编译并运行。

Optional.ofNullable(val1)
                .map(a -> new TypeA())
                .orElse(new TypeB());

所以问题似乎不是map和orElse必须返回相同的类型,这似乎与参数化有关。因此,如果map是TypeA的子类,则map可以发出TypeA,orElse可以发出TypeB。但是它们不能发出不同的List参数化类型。 List 和List 似乎不被认为是彼此的子类型,现在考虑到它们不是。

ResponseEntity 是与ResponseEntity 不同的类型。如果我要从lambda返回简单的JSendResponse和JSendFailResponse,那可能会起作用。但是,我不是,我正在发出不同版本的ResponseEntity,这些版本实际上与层次结构无关。因此,我想这取决于Optional如何支持(或不支持)通配符泛型。我无法将Optional的类型设置为ResponseEntity <?扩展了JSendResponse>,所以我仅限于严格的类型层次结构。

EDIT4:

上面的示例是错误的,因为类型是从原始大小写切换的。我想我现在明白了,谢谢大家。

2 个答案:

答案 0 :(得分:6)

map()发出的类型被推断为JSendFailResponse,但是您在orElse()中提供了另一种类型,并且两种类型必须一致。

明确键入以使用常见类型呼叫map()

.<JSendResponse>map(validationErrors -> new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST))

答案 1 :(得分:1)

如果您检查oracle文档:https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

.ofNullable()方法的签名为:public static <T> Optional<T> ofNullable(T value)

orElse()public T orElse(T other)

因此,这两种方法类型上的参数均为T,而orElse()上没有<? extends T>作为参数,它们两者都应具有T作为类型,因此您的方法不应我猜工作,

您应该尝试以下操作(使用简化示例):

public List<TypeA> getList(TypeA ta) {

        ArrayList<TypeA> typeAinstance = new ArrayList<>();
        return Optional.ofNullable(ta)
                .map(a -> new ArrayList<TypeA>(Arrays.asList(a)))
                .orElse(typeAinstance.getClass().cast(Arrays.asList(new TypeB())));
    }

    public class TypeA {

    }

    public class TypeB extends TypeA {

    }

希望这会有所帮助