使用Java 8 lambdas和Optional的子类

JCN*_*JCN 6 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));
}
Run Code Online (Sandbox Code Playgroud)

编译错误:

"可选"中的orElse(org.springframework.http.ResponseEntity <com.company.util.response.JSendFailResponse>)无法应用于(org.springframework.http.ResponseEntity <com.company.util.response.JSendResponse>)

虽然这段代码(我认为逻辑上是相同的代码)确实编译:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

如果我将validationErrors转换为map 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));
}
Run Code Online (Sandbox Code Playgroud)

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 {

    }
}
Run Code Online (Sandbox Code Playgroud)

编辑3:我以为我根据迄今为止收到的帮助理解了这个问题,但以下代码编译并运行.

Optional.ofNullable(val1)
                .map(a -> new TypeA())
                .orElse(new TypeB());
Run Code Online (Sandbox Code Playgroud)

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

ResponseEntity <JSendResponse>是与ResponseEntity <JSendFailResponse>不同的类型.如果我从lambdas返回普通的JSendResponse和JSendFailResponse,那可能会有效.但我不是,我发布了不同版本的ResponseEntity,它们并没有真正与层次结构相关.所以我想这取决于Optional如何支持(或不支持)通配符泛型.我无法将Optional的类型设置为ResponseEntity <?扩展JSendResponse>,所以我只限于严格的类型层次结构.

EDIT4:

上面的示例不正确,因为类型是从原始案例切换的.我想我现在明白了,谢谢大家.

Boh*_*ian 6

从中map()推断出的类型被推断为JSendFailResponse,但是您提供了不同的类型orElse(),两种类型都必须一致.

map()使用通用类型显式键入以进行调用:

.<JSendResponse>map(validationErrors -> new ResponseEntity<>(validationErrors, HttpStatus.BAD_REQUEST))
Run Code Online (Sandbox Code Playgroud)