Предсказывает Java 8 с дженериками и наследованием - PullRequest
1 голос
/ 03 апреля 2019

У меня есть три объекта Foo Boo Goo с подтипами Boo и Goo суперкласса Foo.

Я использую предикаты для фильтрации списков следующим образом

public class Predicates {

        public static Predicate<Foo> isBoo() {
            foo ->  { 
                  Boo boo = (Boo) foo; 
                  return boo.isBoo();
             };
         }

    public static Predicate<Goo> isGoo() {
            foo ->  { 
                  Goo goo = (Goo) foo; 
                  return goo.isGoo();
             };
     }
}

Что я хочуСледующее - это иметь универсальный тип вместо указанных типов времени компиляции.

public class Predicates {

        public static <T extends Foo> Predicate<T> isBoo() {
            foo ->  { 
                  // check both with instanceof
             };
         }

    public static <T extends Foo> Predicate<T> isGoo() {
            foo ->  { 
                  Goo goo = (Goo) foo; 
                  return boo.isGoo();
             };
     }

    public static <T extends Foo> Predicate<T> isFoo() {
            isGoo().or(isBoo());
     }
}

Кажется невозможным использовать дженерики с предикатами, когда один из них объединяет кратные предикаты с ИЛИ или И.Зная, что предикаты могут иметь разные типы, но все же расширяет суперкласс.

Нужен свет!

1 Ответ

0 голосов
/ 03 апреля 2019

Почему бы вам не определить несколько предикатов для каждого подтипа, добавить эти предикаты в список и, наконец, создать предикат, выполнив or всех предикатов в списке.

public static Predicate<Foo> anotherIsFoo() {
    return predicates.stream()
            .reduce(foo -> false, (a, b) -> a.or(b));
}

В приведенном выше коде предполагается, что predicates - это список, содержащий все предикаты для каждого подтипа.

Полный код выглядит так:

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

class Foo {}
class Boo extends Foo {}
class Goo extends Foo {}

public class Predicates {
    public static List<Predicate<Foo>> predicates = List.of(isGoo(), isFoo());

    public static Predicate<Foo> isGoo() {
        return foo -> foo instanceof Goo;
    }

    public static Predicate<Foo> isBoo() {
        return goo -> goo instanceof Boo;
    }

    public static Predicate<Foo> anotherIsFoo() {
        return predicates.stream()
            .reduce(foo -> false, (a, b) -> a.or(b));
    }

    public static Predicate<Foo> isFoo() {
        return foo -> foo instanceof Foo;
    }

    public static void main(String[] args) {
        List<Foo> list = List.of(new Boo(), new Goo(), new Goo(), new Goo());
        List<Boo> boos = list.stream()
                .filter(Predicates.isBoo())
                .map(boo -> (Boo) boo)
                .collect(Collectors.toList());
        System.out.println(boos.size()); // 1

        List<Goo> goos = list.stream()
                .filter(Predicates.isGoo())
                .map(goo -> (Goo) goo)
                .collect(Collectors.toList());
        System.out.println(goos.size()); //3

        List<Foo> foos = list.stream()
                .filter(Predicates.isFoo())
                .collect(Collectors.toList());
        System.out.println(foos.size()); // 4

        List<Foo> foos1 = list.stream()
                .filter(Predicates.anotherIsFoo())
                .collect(Collectors.toList());
        System.out.println(foos1.size()); // 4
    }
}

Приведенный выше код отвечает на ваш запрос: «У меня не может быть двух разных типов в одном списке, даже если они наследуются от одного и того же суперкласса!»

Для приведенного выше кода требуется Java 9 или выше.

...