Given a collection c
with elements of type T
(or T
's subtypes) return some element e
of type R
from c
so that R
is a subtype of T
.
Motivation: I want to use specific methods of R
on e
.
UPDATE: From the aioobe's answer added to the requirements acceptance of R
's subtypes for e
.
Here is my working implementation:
import java.util.ArrayList;
import java.util.List;
public class ReturnSpecificTypeFromGeneric {
public static <T, R extends T> R findFirstElementOfType(
List<? extends T> elements,
Class<R> requiredClass
) {
for (T element : elements) {
if (requiredClass.isAssignableFrom(element.getClass())) {
// WARNING: Unchecked cast: 'T' to 'R'
//noinspection unchecked
return (R) element; // [1]
}
}
return null;
}
public static void main(String[] args) {
List<Mammal> mammals = new ArrayList<>();
mammals.add(new Elephant());
mammals.add(new WhiteRhino());
mammals.add(new Rhino());
Rhino rhino = findFirstElementOfType(mammals, Rhino.class);
System.out.println(rhino.getClass()); // returns: class WhiteRhino
}
}
class Mammal {}
class Elephant extends Mammal {}
class Rhino extends Mammal {}
class WhiteRhino extends Rhino {}
Questions:
[1]
) be avoided, and how, and should it be cared about?That code looks reasonable to me.
You could "hide" the cast by instead using requiredClass.cast(element)
.
Basically the same solution, but you could express it using streams as follows:
public static <T, R extends T> R findFirstElementOfType(
List<? extends T> elements,
Class<R> requiredClass
) {
return elements.stream()
.filter(requiredClass::isInstance)
.findFirst()
.map(requiredClass::cast)
.orElseThrow(NoSuchElementException::new);
}
or .orElse(null)
in the end, if you want the exact behavior of your original snippet.