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());
}
并且在原始示例中,编译器不需要确定 Stream
和 Iterator
来自同一个对象这一事实。引用同一对象的两个单独的表达式被捕获为两个不同的类型。
我正在尝试解决一个看起来相对简单的问题。似乎没有一种直观的方法可以做到这一点,或者我在这里遗漏了一些东西。
考虑用这种方法找到主图,如果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());
}
并且在原始示例中,编译器不需要确定 Stream
和 Iterator
来自同一个对象这一事实。引用同一对象的两个单独的表达式被捕获为两个不同的类型。