【问题标题】:In Java, can I make a predicate that applies a filter on more than one object?在 Java 中,我可以创建一个对多个对象应用过滤器的谓词吗?
【发布时间】:2020-03-03 08:20:49
【问题描述】:

我有一个谓词用于过滤相同实体对象的列表:

Predicate<DWHDeal> companyFilter = i -> i.getCompany().equals(company);

我还必须在基于之前实体构建 DTOS 的 DTO 列表中应用相同的过滤器,在完全相同的字段上使用完全相同的条件:

Predicate<DWHDealDTO> companyFilterDTO = i -> i.getCompany().equals(company);

是否可以在不实例化两个不同谓词的情况下实现这一点?如果可能的话,我想通过只创建一个Predicate 来实现这一点。

【问题讨论】:

  • DWHDealDTODWHDeal 是否相关? (就像扩展同一个类)
  • getCompany() 在两种情况下是否返回相同的类型?
  • @ernest_k 不,不幸的是,它们没有扩展相同的类。但它们的字段大多相同。
  • 那么定义一个通用接口呢? (即由两个类实现)
  • 规则没有什么不同,例如使用普通类实现Predicate 或尝试编写一个同时接受DWHDealDWHDealDTO 作为参数的方法。如果这些类没有公共接口或声明公共方法的超类,则它们没有公共方法,只有两个不相关的方法恰好具有相同的名称。

标签: java lambda java-8 predicate


【解决方案1】:

假设getCompany() 返回一个String,您可以创建Predicate&lt;String&gt;

Predicate<String> predicate = s -> s.equals(company);

然后像这样使用它:

list.stream()
    .filter(dto -> predicate.test(dto.getCompany()))
    ...

但是没有太多好处,因为它需要几乎相同的代码。

【讨论】:

  • 它确实有好处。不用为每个 DTO 创建 Predicate,只需一个 Predicate 就足够了,这种方法适用于所有 DTO。所以这会带来更好的代码可重用性。编写的代码越少,管理的代码就越少。
  • @KetanR 这仍然为每个 DTO 提供一个谓词,准确地说,它还有一个谓词。
【解决方案2】:

如果仅检查相等性,则可以使用静态谓词 isEqual(Object targetRef)。见java文档https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html#isEqual-java.lang.Object-

class StudentView{
    String name;

    public StudentView(String name) {
        this.name = name;
    }
}
class StudentDTO{
    String name;

    public StudentDTO(String name) {
        this.name = name;
    }
}

public void testPredicate(){
    StudentView studentView= new StudentView("John");
    StudentDTO studentDTO = new StudentDTO("Sam");
    Predicate p = Predicate.isEqual("John");
    System.out.println("Test for Student View "+ p.test(studentView.name));
    System.out.println("Test for Student DTO "+ p.test(studentDTO.name));


}

【讨论】:

    【解决方案3】:

    我认为您在使用 Predicate 之前需要一个 Function&lt;T,R&gt;

    函数有两个概念。首先是java.util.function.Function,它接受one 参数并产生result。第二个是流中间操作映射,通过提供的函数将中的每个元素转换为另一个对象

    在您的情况下,Function 应如下所示:

    Function<DWHDeal, DWHDealDTO> myFunction = new Function<DWHDeal, DWHDealDTO>() {
      public DWHDealDTO apply(DWHDeal t) {
        return ... ;
      }
    };
    

    我尝试了以下基本程序并成功:

    static class DWHDeal{
        String name;
    
        public DWHDeal(String name) {
          this.name = name;
        }
      }
      static class DWHDealDTO{
        String name;
    
        public DWHDealDTO(String name) {
          this.name = name;
        }
      }
    
      static Predicate<DWHDealDTO> companyFilter = i -> i.name.equalsIgnoreCase("com");
      public static void main(String[] args) {
        Function<DWHDeal, DWHDealDTO> myFunction = new Function<DWHDeal, DWHDealDTO>() {
          public DWHDealDTO apply(DWHDeal t) {
            return new DWHDealDTO("com");
          }
        };
        DWHDeal newDWHDealDTOObj = new DWHDeal("com");
        System.out.println(companyFilter.test(myFunction.apply(newDWHDealDTOObj)));  //Works
      }
    

    【讨论】:

      【解决方案4】:

      正如 cmets 中所建议的,通用接口将是首选解决方案。

      我猜你可以做这样的事情,但公平地说,这很丑。

      private String getCompany(Object o) {
          if(o instanceof DWHDeal)
              return ((DWHDeal) o).getCompany();
          else
              return ((DWHDealDTO) o).getCompany();
      }
      

      Predicate<Object> companyFilter = i -> getCompany(i).equals(company);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-03-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多