Lambda inside orElseGet in bounded wildcard generics

Lambda inside orElseGet in bounded wildcard generics

我的部分代码如下所示:

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

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

有一个 enum,通过它我使用来自 entityServiceFactory 的静态方法获得服务 class。然后我调用方法 getFooArgs(...),即 returns Optional。然后我想使用 EntityService 方法映射它或使用不带参数的方法来获取 "default" 值,当 getFooArgs return空可选。

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

遗憾的是我从 IDE 得到了 Bad return type in lambda expression: List<capture of ? extends AbstractEntityDto> cannot be converted to 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();

你能解释一下为什么会这样吗?我认为它与 ? 和泛型有关,但我认为通过使用 ? 很多类型的限制都会消失。 如果代码太少无法解决,请告诉我。

我什至没有试图找出为什么编译器不接受这个结构。当谈到类型推断和通配符时,很多看起来应该有效的东西却没有。

最简单的解决方法是为 map:

的泛型调用提供显式类型
return getFooArgs(bar)
    .<List<? extends AbstractEntityDto>>map(entityService::getListWithFooArgs)
    .orElseGet(entityService::getListNoArgs);

一般来说,你应该avoid wildcards in return types。随身携带通配符没有任何价值。相比之下,当您真正拥有处理 List<ConcreteEntityDto> 的代码并且需要将其传递给应该能够处理更多情况的方法时,使用通配符声明 参数类型 , 像 List<? extends AbstractEntityDto>, 接受 List<ConcreteEntityDto>List<SomeOtherEntityDto>, 是非常有用的。

注意给定一个

List<? extends AbstractEntityDto> list = …

你可以做到

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

用于不尝试修改列表的后续处理。由 unmodifiableList 编写的包装器 return 可防止任何尝试将元素插入到 AbstractEntityDto 的未知子类型列表中,但可以保证所有 AbstractEntityDto 的 return 个实例查询方法。这就是此类型更改有效的原因。