Java 8 个带可选的通用集合

Java 8 generic collections with optionals

我正在尝试解决一个看起来相对简单的问题。似乎没有一种直观的方法可以做到这一点,或者我在这里遗漏了一些东西。

考虑用这种方法找到主图,如果none存在,return第一张图-

public Image findMainImage(Collection<? extends Image> images) {
    if (images == null || images.isEmpty()) return null
    return images.stream()
                 .filter(Image::isMain)
                 .findFirst()
                 .orElse(images.iterator().next())
}

我收到一个错误 - orElse(capture<? extends Image>) in Optional cannot be applied

任何关于这方面的指导都很好。

假设你有一个List<? extends Number>。您无法将 任何 号码添加到此列表,因为它可能是 List<Integer> 而您尝试添加的号码可能是 Float

出于同样的原因,Optional<T> 的方法 orElse(T t) 需要一个 T。由于所讨论的 Optional 是一个 Optional<? extends Image>,编译器无法确定 images.iterator().next() 是正确的类型。

我通过输入 .map(t -> (Image) t):

来编译它
return images.stream()
             .filter(Image::isMain)
             .findFirst()
             .map(t -> (Image) t)
             .orElse(images.iterator().next());

事实上,出于某种我无法理解的原因,即使没有强制转换它也能工作。仅使用

.map(t -> t)

似乎可以做到这一点。

修复它的一种方法是使用类型参数:

public <I extends Image> I findMainImage(Collection<I> images) {
    if (images == null || images.isEmpty()) return null;
    return images.stream()
                 .filter(Image::isMain)
                 .findFirst()
                 .orElse(images.iterator().next());
}

因为然后(对于编译器)Optional 肯定具有与 images.

相同的类型参数

如果需要,我们可以将其用作 capturing helper

public Image findMainImage(Collection<? extends Image> images) {
    return findMainImageHelper( images );
}

private <I extends Image> I findMainImageHelper(Collection<I> images) {
    // ...
}

就我个人而言,我只会使用通用版本,因为这样您就可以执行以下操作,例如:

List<ImageSub> list = ...;
ImageSub main = findMainImage( list );

基本上......它最初无法编译的原因是为了防止你做这样的事情:

public Image findMainImage(
    Collection<? extends Image> images1,
    Collection<? extends Image> images2
) {
    return <strong>images1</strong>.stream()
                  .filter(Image::isMain)
                  .findFirst()
                  .orElse(<strong>images2</strong>.iterator().next());
}

并且在原始示例中,编译器不需要确定 StreamIterator 来自同一个对象这一事实。引用同一对象的两个单独的表达式被捕获为两个不同的类型。