Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Lambdas - equivalent of c# OfType

I am learning the new java 8 features now, after 4 years exclusively in C# world, so lambdas are on top for me. I am now struggling to find an equivalent for C#'s "OfType" method.

What I have is a List myNodes , I want to get a List out of it, where Node is an interface, and SpecificNode is implementing it.

In C# it would be

IList<INode> myNodes = new List<INodes>(){new SpecificNode(), new OtherNode()}
IList<SpecificNode> specificNodes = myNodes.OfType<SpecificNode>()
like image 960
Petr Osipov Avatar asked Aug 01 '14 09:08

Petr Osipov


2 Answers

Instead of first filtering and then mapping the stream to the desired target type, it is possible to do both in a single call to the stream via flatMap and this small helper function:

private static <Target extends Base, Base> Function<Base, Stream<Target>> ofType(Class<Target> targetType) {
    return value -> targetType.isInstance(value) ? Stream.of(targetType.cast(value)) : Stream.empty();
}

This Function basically checks for a element if a cast is possible and then casts it, returning a stream with the single casted element or an empty stream if the cast was not possible.

Stream.of(1, 2, 3, "Hallo", 4, 5, "Welt")
    .flatMap(ofType(String.class))
    .forEach(System.out::println);

With the help of a flatMap operation all returned streams can be concatenated.

I assume that a separated check and cast are easier to understand and maybe even faster in execution, this is just a prove of concept for a single stream operation.

like image 194
Lukas Körfer Avatar answered Sep 18 '22 13:09

Lukas Körfer


There is no exact match in Java for the .OfType<T>() method, but you can use the Java8's filtering features:

IList<INode> myNodes = new ArrayList<INode>();
myNodes.add(new SpecificNode());
myNodes.add(new OtherNode());

List<SpecificNode> filteredList = myNodes.stream()
                                         .filter(x -> x instanceof SpecificNode)
                                         .map(n -> (SpecificNode) n)
                                         .collect(Collectors.toList());

If you want to get of the explicit cast, you can do:

List<SpecificNode> filteredList = myNodes.stream()
                                             .filter(SpecificNode.class::isInstance)
                                             .map(SpecificNode.class::cast)
                                             .collect(Collectors.toList());
like image 24
Konstantin Yovkov Avatar answered Sep 20 '22 13:09

Konstantin Yovkov