【问题标题】:Predicates java 8 with generics and inheritance具有泛型和继承的谓词 java 8
【发布时间】:2019-04-03 14:01:01
【问题描述】:

我拥有三个 Foo Boo Goo 对象,它们具有 Foo 超类的 Boo 和 Goo 子类型。

我正在使用谓词来过滤列表,如下所示

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

当使用 OR 或 AND 组合多个谓词时,似乎不可能将泛型与谓词一起使用。知道谓词可能有不同的类型,但仍然扩展了超类。

需要光!

【问题讨论】:

  • 为什么不简单地public static Predicate&lt;? super Foo&gt; isBoo() {?
  • 我不知道为什么,但在编译时。我不能在同一个列表中有两种不同的类型,即使它们继承自同一个超类!
  • 我不确定您为什么要尝试使用通配符来完成谓词可能接受的值类型。该类型参数是关于谓词可以处理哪种对象的语句,而不是谓词将为哪种对象返回 true 的语句。我认为你在这里混淆了这两件事。鉴于上面的示例,您可以在任何地方使用Predicate&lt;Object&gt;,因为“instanceof”适用于任何对象。
  • 例如,如果 (Boo) 强制转换有效,isBoo() 会返回 false 吗?咕也一样。我认为您应该尝试使代码示例变得不那么琐碎,并且更现实地表明您的意图可能有一些实际用途。
  • 也许您应该添加一些代码,该谓词将用于实现一些实际操作。

标签: java generics java-8 predicate


【解决方案1】:

为什么不为每个子类型定义多个谓词,将这些谓词添加到一个列表中,最后通过对列表中所有谓词进行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 或更高版本。

【讨论】:

  • 我真的很喜欢你的提议。但是我的子类中有属性,我想在谓词中访问这些属性以应用 test()。仅检查超类类型对象的实例时,无法满足此要求,并且我无权访问子属性
猜你喜欢
  • 2021-10-27
  • 1970-01-01
  • 1970-01-01
  • 2011-03-06
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
  • 2020-05-17
  • 1970-01-01
相关资源
最近更新 更多