【问题标题】:Lambda inside orElseGet in bounded wildcard genericsorElseGet 中的 Lambda 有界通配符泛型
【发布时间】:2020-03-05 07:59:45
【问题描述】:

我的部分代码如下所示:

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

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

有一个 enum,我通过它使用 entityServiceFactory 的静态方法获取服务类。然后我调用方法 getFooArgs(...),它返回 Optional。然后我想使用 EntityService 方法映射它或使用没有 args 的方法来获取“默认”值,当 getFooArgs 返回空 Optional 时。

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

很遗憾,我从我的 IDE 中得到了 Bad return type in lambda expression: List&lt;capture of ? extends AbstractEntityDto&gt; cannot be converted to List&lt;capture of ? extends AbstractEntityDto&gt;。我要做的是:

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

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

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

【问题讨论】:

  • 封闭方法的返回类型是什么?
  • 我是List&lt;? extends AbstractEntityDto&gt;

标签: java generics lambda optional


【解决方案1】:

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

最简单的解决方法是为map 的泛型调用提供显式类型:

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

一般情况下,您应该avoid wildcards in return types。随身携带通配符没有任何价值。相反,当您确实有处理List&lt;ConcreteEntityDto&gt; 的代码并且需要将其传递给应该能够处理更多情况的方法时,使用通配符声明一个参数类型,例如List&lt;? extends AbstractEntityDto&gt; ,接受List&lt;ConcreteEntityDto&gt;List&lt;SomeOtherEntityDto&gt;,非常有用。

注意,给定一个

List<? extends AbstractEntityDto> list = …

你可以的

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

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

【讨论】:

  • “一般来说,你应该避免在返回类型中使用通配符。” ... this.
  • 感谢您的回答。除了解决我的问题,您还提供了一些有用的信息。在那种情况下,我觉得不重新使用通配符不是一种选择。我不得不返回EntityService&lt;? extends AbstractEntityDto&gt;,因为我为AbstractEntityDto 的每个子类实现了EntityService。如果静态方法返回EntityService&lt;AbstractEntityDto&gt;,它将与EntityService&lt;ConcreteEntityDto&gt; 不兼容。不过,说到收藏,我同意你的看法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-08
相关资源
最近更新 更多