简体   繁体   English

Java 8 Lambdas - 相当于c#OfType

[英]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. 我现在正在学习新的Java 8功能,经过4年专门在C#世界,所以lambdas对我来说是最重要的。 I am now struggling to find an equivalent for C#'s "OfType" method. 我现在正在努力寻找C#的“OfType”方法的等价物。

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. 我所拥有的是List myNodes,我想从中获取一个List,其中Node是一个接口,而SpecificNode正在实现它。

In C# it would be 在C#中它会是

IList<INode> myNodes = new List<INodes>(){new SpecificNode(), new OtherNode()}
IList<SpecificNode> specificNodes = myNodes.OfType<SpecificNode>()

There is no exact match in Java for the .OfType<T>() method, but you can use the Java8's filtering features: Java中没有.OfType<T>()方法完全匹配,但您可以使用Java8的过滤功能:

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

I was having the same issue. 我遇到了同样的问题。 This is what I came up with, but since java doesn't do extension methods (maybe in 10 more years?), it is a static method. 这就是我提出的,但由于java不做扩展方法(可能还有10年?),它是一个静态方法。 This is using the stream API, though there isn't a particular reason you must do that. 这是使用流API,但没有特别的原因你必须这样做。 The same basic checks would work just fine in a for loop with a preallocated ArrayList. 相同的基本检查在带有预分配ArrayList的for循环中可以正常工作。

@SuppressWarnings("unchecked")
private static <T> List<T> ofType(Class<?> out, List<Object> list) {
    return list.stream().filter(x -> out.isAssignableFrom(x.getClass()))
               .map(x -> (T) x) // unchecked
               .collect(Collectors.toList());
}

// fyi this code uses "boon" library
List<Object> objlist = list("ABC", 3, "def", -30.39); 
puts("strings=", ofType(String.class, objlist));  // strings= [ABC, def] 
puts("integers=", ofType(Integer.class, objlist)); // integers= [3]

Here is the version that doesn't use streams. 这是不使用流的版本。 It works just the same, but some of the fun with streams is that ... you might be able to stream them, if thats your kind of thing. 它的工作原理是一样的,但是流的一些乐趣是......你可能能够流式传输它们,如果这是你的事情。 I don't find it useful very often except for helpers like this. 除了像这样的助手之外,我并不经常发现它很有用。

private static <T> List<T> ofType(Class<?> out, List<Object> list) {
    List<T> outList = new ArrayList<T>(list.size());
    for(Object o : list) {
        if ( out.isAssignableFrom(o.getClass())) {
            outList.add((T)o);
        }
    }
    return outList;
}

You can create a Function containing the Stream pipeline, which reduces its invocation. 您可以创建一个包含Stream管道的Function,从而减少其调用。

    Function<List<INode>,List<SpecificNode>> ofSub =
       bl -> bl.stream()
               .filter(x -> x instanceof SpecificNode)
               .map(n -> (SpecificNode) n)
               .collect(Collectors.toList());

For instance: 例如:

    for( SpecificNode s: ofSub.apply( myNodes ) ){
         //...
    }

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: 不是先过滤然后将流映射到所需的目标类型,而是可以通过flatMap对这个流进行单次调用以及这个小辅助函数:

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. 如果可以进行强制转换,则此Function基本上检查元素,然后对其进行强制转换,返回具有单个铸造元素的流或如果无法进行强制转换则返回空流。

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. flatMap操作的帮助下,所有返回的流都可以连接在一起。

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. 我假设分离的检查和转换更容易理解,甚至可能更快执行,这只是单个流操作的概念证明。

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

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