有界通配符泛型中orElseGet内的Lambda

3

我的代码的一部分看起来像这样:

EntityTypeEnum entityType = EntityTypeEnum.fromName(entityTypeName).orElseThrow(...);
EntityService<? extends AbstractEntityDto> entityService = entityServiceFactory.getEntityService(importType);

return getFooArgs(bar)
    .map(entityService::getListWithFooArgs)
    .orElseGet(()->entityService.getListNoArgs());

我可以使用从 entityServiceFactory 中的静态方法获取服务类,这是通过 enum 实现的。 然后我调用方法 getFooArgs(...),它返回 Optional< FooArg >。 然后,我想使用 EntityService 方法映射它,或者在 getFooArgs 返回空 Optional 时使用不带参数的方法获取“默认”值。

public interface EntityService<T extends AbstractEntityDto> {
    List<T> getListNoArgs();
    List<T> getListWithFooArgs(FooArg fooArgs);
}

遗憾的是,我从我的IDE中获得了lambda表达式中的错误返回类型:List<capture of ? extends AbstractEntityDto>无法转换为List<capture of ? extends AbstractEntityDto>。 我所要做的是:

Optional<List<? extends AbstractEntityDto>> listOptional = getFooArgs(bar)
        .map(entityService::getListWithFooArgs);

if(listOptional.isPresent())
    return listOptional.get();
else
    return entityService.getListNoArgs();

你能解释一下为什么会发生这种情况吗?我认为它与?和泛型有关,但我以为使用?会消除很多类型限制。如果代码太少无法理解,请告诉我。

封闭方法的返回类型是什么? - Sweeper
这是 List<? extends AbstractEntityDto> - ogarogar
1个回答

4

我甚至不试图找出编译器为什么不接受这个结构。在类型推断和通配符方面,许多看起来应该有效的东西实际上都是无效的。

最简单的修复方法是为泛型调用map提供一个明确的类型:

return getFooArgs(bar)
    .<List<? extends AbstractEntityDto>>map(entityService::getListWithFooArgs)
    .orElseGet(entityService::getListNoArgs);

一般而言,你应该避免在返回类型中使用通配符。携带通配符没有任何意义。相反,当你真正处理 List<ConcreteEntityDto> 代码并需要将其传递给能够处理更多情况的方法时,使用通配符声明参数类型是非常有用的,比如 List<? extends AbstractEntityDto>,可以接受 List<ConcreteEntityDto>List<SomeOtherEntityDto>

请注意,假设有一个

List<? extends AbstractEntityDto> list = …

你可以做到

List<AbstractEntityDto> view = Collections.unmodifiableList(list);

用于后续处理但不尝试修改列表的情况。由unmodifiableList返回的包装器阻止任何尝试向未知子类型为AbstractEntityDto的列表插入元素,但可以保证为所有查询方法返回AbstractEntityDto实例。这就是为什么此类型更改是有效的原因。


通常情况下,您应该避免在返回类型中使用通配符。 - scottb
谢谢您的答复。除了解决我的问题,您还提供了一些有用的信息。在这种情况下,我感觉不返回通配符不是一个选项。我必须返回EntityService <? extends AbstractEntityDto>,因为我为AbstractEntityDto的每个子类实现了EntityService。如果静态方法返回EntityService<AbstractEntityDto>,它将与EntityService<ConcreteEntityDto>不兼容。不过,当涉及到集合时,我同意您的看法。 - ogarogar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接