Jednym ze sposobów, aby to naprawić jest użycie parametr typu:
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());
}
Bo wtedy (kompilator) Optional
pewno ma ten sam typ argumentu jako images
.
I moglibyśmy użyć jej jako capturing helper jeśli chcieliśmy:
public Image findMainImage(Collection<? extends Image> images) {
return findMainImageHelper(images);
}
private <I extends Image> I findMainImageHelper(Collection<I> images) {
// ...
}
Osobiście, chciałbym po prostu użyć wersji rodzajowy, bo wtedy można zrobić np:
List<ImageSub> list = ...;
ImageSub main = findMainImage(list);
Zasadniczo ... powodem, dla którego nie kompiluje się oryginalnie, jest powstrzymanie cię przed zrobieniem czegoś takiego:
public Image findMainImage(
Collection<? extends Image> images1,
Collection<? extends Image> images2
) {
return images1.stream()
.filter(Image::isMain)
.findFirst()
.orElse(images2.iterator().next());
}
I w oryginalnym przykładzie kompilator nie musi określać faktu, że zarówno Stream
, jak i Iterator
pochodzą z tego samego obiektu. Dwa oddzielne wyrażenia odwołujące się do tego samego obiektu zostają przechwycone do dwóch oddzielnych typów.
Prawdopodobnie działałoby to, gdyby była to tylko 'Kolekcja', ale sposób działania generyków, 'Opcjonalnie .orElse' może akceptować tylko' T'. –
Czy możesz zmienić podpis metody na "publiczny T findMainImage (kolekcja )' –
Misha
@misha Dostaję jak działa, zmieniając podpis, jestem bardziej zainteresowany zrozumieniem tego, co za tym stoi. – sanz