繁体   English   中英

Java 8 Lambdas - 相当于c#OfType

[英]Java 8 Lambdas - equivalent of c# OfType

我现在正在学习新的Java 8功能,经过4年专门在C#世界,所以lambdas对我来说是最重要的。 我现在正在努力寻找C#的“OfType”方法的等价物。

我所拥有的是List myNodes,我想从中获取一个List,其中Node是一个接口,而SpecificNode正在实现它。

在C#中它会是

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

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

如果你想得到明确的演员表,你可以这样做:

List<SpecificNode> filteredList = myNodes.stream()
                                             .filter(SpecificNode.class::isInstance)
                                             .map(SpecificNode.class::cast)
                                             .collect(Collectors.toList());

我遇到了同样的问题。 这就是我提出的,但由于java不做扩展方法(可能还有10年?),它是一个静态方法。 这是使用流API,但没有特别的原因你必须这样做。 相同的基本检查在带有预分配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]

这是不使用流的版本。 它的工作原理是一样的,但是流的一些乐趣是......你可能能够流式传输它们,如果这是你的事情。 除了像这样的助手之外,我并不经常发现它很有用。

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;
}

您可以创建一个包含Stream管道的Function,从而减少其调用。

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

例如:

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

不是先过滤然后将流映射到所需的目标类型,而是可以通过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();
}

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

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

flatMap操作的帮助下,所有返回的流都可以连接在一起。

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

暂无
暂无

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

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