简体   繁体   English

带有选项的Java 8泛型集合

[英]Java 8 generic collections with optionals

I have a relatively simple looking problem that I am trying to solve. 我有一个相对简单的问题,我试图解决。 There doesn't seem to be an intuitive way to do this or, I am missing something here. 似乎没有直观的方法来做到这一点,或者我在这里遗漏了一些东西。

Consider this method to find the main image and if none exists, return first image- 考虑使用此方法查找主图像,如果不存在,则返回第一张图像 -

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())
}

I get an error - orElse(capture<? extends Image>) in Optional cannot be applied 我收到错误 - orElse(capture<? extends Image>) in Optional cannot be applied

Any direction on this would be great. 任何方向都会很棒。

One way to fix it is to use a type parameter: 解决它的一种方法是使用类型参数:

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());
}

Because then (to the compiler) the Optional definitely has the same type argument as images . 因为那时(对编译器) Optional肯定具有与images相同的类型参数。

And we could use that as a capturing helper if we wanted: 如果我们想要,我们可以将其用作捕获助手

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

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

Personally, I would just use the generic version because then you can do eg: 就个人而言,我只会使用通用版本,因为那样你可以做到:

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

Basically...the reasoning for why it doesn't compile originally is to keep you from doing something like this: 基本上......原因不能编译的原因是为了防止你做这样的事情:

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

And in the original example the compiler doesn't need to determine the fact that both the Stream and the Iterator come from the same object. 在原始示例中,编译器不需要确定StreamIterator都来自同一对象的事实。 Two separate expressions that reference the same object get captured to two separate types. 引用同一对象的两个单独表达式被捕获到两个不同的类型。

Suppose you have a List<? extends Number> 假设你有一个List<? extends Number> List<? extends Number> . List<? extends Number> You could not add any number to this list, because it could be a List<Integer> and the number you are attempting to add could be a Float . 您无法在此列表中添加任何数字,因为它可能是List<Integer> ,您尝试添加的数字可能是Float

For the same reason, the method orElse(T t) of Optional<T> requires a T . 出于同样的原因, Optional<T>的方法orElse(T t)需要T Since the Optional in question is an Optional<? extends Image> 由于Optional的问题是一个Optional<? extends Image> Optional<? extends Image> , the compiler can't be sure that images.iterator().next() is of the right type. Optional<? extends Image> ,编译器无法确定images.iterator().next()是否为正确的类型。

I got this to compile by putting in .map(t -> (Image) t) : 我通过放入.map(t -> (Image) t)来编译它:

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

In fact, for some reason I can't understand, it works even without the cast. 事实上,由于某种原因,我无法理解,即使没有演员,它也能奏效。 Just using 只是用

.map(t -> t)

seems to make this work. 似乎使这项工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM