Подтвердить что ты не робот

Java 8 Lambdas - эквивалент С# OfType

Я изучаю новые функции java 8 сейчас, через 4 года исключительно в С# мире, поэтому lambdas на вершине для меня. Теперь я пытаюсь найти эквивалент для метода С# "OfType".

Что у меня есть список myNodes, я хочу получить из него список, где Node является интерфейсом, а SpecificNode его реализует.

В С# это будет

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

Ответ 1

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

Ответ 2

У меня была такая же проблема. Это то, что я придумал, но поскольку java не использует методы расширения (может быть, через 10 лет?), Это статический метод. Это использует API потока, хотя нет конкретной причины, по которой вы должны это сделать. Те же основные проверки будут работать очень хорошо в цикле for с предварительно распределенным ArrayList.

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

Ответ 3

Вы можете создать функцию, содержащую конвейер Stream, что уменьшает его вызов.

    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 ) ){
         //...
    }

Ответ 4

Вместо первой фильтрации и последующего сопоставления потока с желаемым типом цели можно выполнить как один вызов потока через 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 все возвращенные потоки могут быть объединены.

Я предполагаю, что выделенная проверка и литье легче понять и, возможно, даже быстрее в исполнении, это всего лишь доказательство концепции для одной операции потока.