title: How to apply composite BiPredicate in anyMatch() java 8 streams
body: <p>I have two Lists. One I created from Database and one from Csv file. Now I want to collect records in a list that contain both in database and csv file. I wrote code like below</p>
  
  <pre><code>BiPredicate&lt;Trainee, Trainee&gt; sameTrainee = (dbTrainee, csvTrainee) -&gt; {
  
      String dbTraineeFirstName = dbTrainee.getFirstName();
      String dbTraineeLastName = dbTrainee.getLastName();
      String dbTraineeEmail = dbTrainee.getEmail();
      LocalDateTime dbTraineeCompletionDate = dbTrainee.getSessionDateTime();
      String text = dbTraineeCompletionDate.format(DATE_TIME_FORMATTER); 
      LocalDateTime dbTraineeSessionDateTime = LocalDateTime.parse(text);
      String dbTraineePhoneNumber = dbTrainee.getPhoneNumber();
      String dbTraineeSsn = dbTrainee.getSocialSecurityLastFour();
      String dbTraineeStreetOne = dbTrainee.getStreetOne();
      String dbTraineeCity = dbTrainee.getCity();
  
      String csvTraineeFirstName = csvTrainee.getFirstName();
      String csvTraineeLastName = csvTrainee.getLastName();
      String csvTraineeEmail = csvTrainee.getEmail();
      LocalDateTime csvTraineeSessionDateTime = csvTrainee.getSessionDateTime();
      String csvTraineePhoneNumber = csvTrainee.getPhoneNumber();
      String csvTraineeSsn = csvTrainee.getSocialSecurityLastFour();
      String csvTraineeStreetOne = csvTrainee.getStreetOne();
      String csvTraineeCity = csvTrainee.getCity();
  
      int dbTraineeSsnLength = dbTraineeSsn.length();
      int csvTraineeSsnLength = csvTraineeSsn.length();
  
      if (dbTraineeSsnLength != csvTraineeSsnLength) {
          if (dbTraineeSsnLength == 4 &amp;&amp; dbTraineeSsn.startsWith("0")) {
              String dbTraineeSsnLast3Digits = dbTraineeSsn.substring(dbTraineeSsn.length() - 3);
              if (csvTraineeSsnLength == 3 &amp;&amp; csvTraineeSsn.endsWith(dbTraineeSsnLast3Digits)) {
                  csvTraineeSsn = "0" + csvTraineeSsn;
              }
          }
      }
  
      return dbTraineeFirstName.equals(csvTraineeFirstName) 
              &amp;&amp; dbTraineeLastName.equals(csvTraineeLastName)
              &amp;&amp; dbTraineeEmail.equals(csvTraineeEmail) 
              &amp;&amp; dbTraineeSessionDateTime.equals(csvTraineeSessionDateTime)
              &amp;&amp; dbTraineePhoneNumber.equals(csvTraineePhoneNumber)
              &amp;&amp; dbTraineeSsn.equals(csvTraineeSsn) 
              &amp;&amp; dbTraineeStreetOne.equals(csvTraineeStreetOne)
              &amp;&amp; dbTraineeCity.equals(csvTraineeCity);
  };
  </code></pre>
  
  <p>and called it like </p>
  
  <pre><code>List&lt;Trainee&gt; foundInBothList = dbMonthlyTraineeList.stream()
                      .filter(dbTrainee -&gt; csvTraineeList.stream()
                          .anyMatch(csvTrainee -&gt; {
                              return sameTrainee.test(dbTrainee, csvTrainee);
                          })
                      ).collect(Collectors.toList());
  
  List&lt;Trainee&gt; notInFileList = dbMonthlyTraineeList.stream()
                      .filter(dbTrainee -&gt; csvTraineeList.stream()
                          .noneMatch(csvTrainee -&gt; {
                              return sameTrainee.test(dbTrainee, csvTrainee);
                          })
                      ).collect(Collectors.toList());
  </code></pre>
  
  <p>It works fine. But as my BiPredicate is getting long and untidy. So I made a class and collect all the predicates in a Collection like below</p>
  
  <pre><code>public class PlcbMonthlyReportStatisticsBiPredicates {
  
      public static BiPredicate&lt;Trainee, Trainee&gt; isValidFirstName() {
          return (dbTrainee, csvTrainee) -&gt; {
              String dbTraineeFirstName = dbTrainee.getFirstName();
              String csvTraineeFirstName = csvTrainee.getFirstName();
              return dbTraineeFirstName.equals(csvTraineeFirstName);
          };
      }
  
      public static BiPredicate&lt;Trainee, Trainee&gt; isValidSsn() {
          return (dbTrainee, csvTrainee) -&gt; {
              String dbTraineeSsn = dbTrainee.getSocialSecurityLastFour();
              String csvTraineeSsn = csvTrainee.getSocialSecurityLastFour();
              ...
              return dbTraineeSsn.equals(csvTraineeSsn);
          };
      }
  
      ....
  
      public static List&lt;BiPredicate&lt;Trainee, Trainee&gt;&gt; getAllBiPredicates() {
  
          List&lt;BiPredicate&lt;Trainee, Trainee&gt;&gt; allPredicates = Arrays.asList(
                  isValidFirstName(),
                  isValidSsn(),
                  ... 
          );  
          return allPredicates;
      }
  }
  </code></pre>
  
  <p>Now I Collect all the predicates but how can I apply these predicates in my anyMatch() and noneMatch(). I tried this but of-cources getting error</p>
  
  <pre><code>List&lt;Trainee&gt; foundInBothList1 = dbMonthlyTraineeList.stream()
      .filter(dbTrainee -&gt; csvTraineeList.stream()
          .anyMatch(csvTrainee -&gt; {
              List&lt;BiPredicate&lt;Trainee, Trainee&gt;&gt; allBiPredicates = getAllBiPredicates();
              return allBiPredicates.stream().reduce(BiPredicate::and).orElse((x,y)-&gt;true);  //error
  
          })
      ).collect(Collectors.toList());
  </code></pre>
  
  <p>How can I apply this. Is my approach is right?</p>
  
  <p>**Edit</p>
  
  <hr>
  
  <pre><code>@Entity
  public class Trainee {
  
      private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
  
      private LocalDateTime sessionDateTime;
      private String firstName;
      ....
  
      @Override
      public boolean equals(Object otherObject) {
  
          // Are the same?
          if (this == otherObject) {
              return true;
          }
          // Is otherObject a null reference?
          if (otherObject == null) {
              return false;
          }
          // Do they belong to the same class?
          if (this.getClass() != otherObject.getClass()) {
              return false;
          }
  
          // Get the reference of otherObject in a otherTrainee variable
          Trainee otherTrainee = (Trainee)otherObject;
  
          LocalDateTime dbTraineeCompletionDate = this.getSessionDateTime();
          String text = dbTraineeCompletionDate.format(DATE_TIME_FORMATTER); 
          LocalDateTime dbTraineeSessionDateTime = LocalDateTime.parse(text);
  
          String dbTraineeSsn = this.socialSecurityLastFour;
          String csvTraineeSsn = otherTrainee.getSocialSecurityLastFour();
  
          int dbTraineeSsnLength = dbTraineeSsn.length();
          int csvTraineeSsnLength = csvTraineeSsn.length();
  
          if (dbTraineeSsnLength != csvTraineeSsnLength) {
              if (dbTraineeSsnLength == 4 &amp;&amp; dbTraineeSsn.startsWith("0")) {
                  String dbTraineeSsnLast3Digits = dbTraineeSsn.substring(dbTraineeSsn.length() - 3);
                  if (csvTraineeSsnLength == 3 &amp;&amp; csvTraineeSsn.endsWith(dbTraineeSsnLast3Digits)) {
                      csvTraineeSsn = "0" + csvTraineeSsn;
                  }
              }
          }
  
          boolean isEqual = (this.firstName.equals(otherTrainee.firstName)
              &amp;&amp; this.lastName.equals(otherTrainee.lastName)
              &amp;&amp; this.email.equals(otherTrainee.email) 
              &amp;&amp; dbTraineeSessionDateTime.equals(otherTrainee.sessionDateTime)
              &amp;&amp; this.phoneNumber.equals(otherTrainee.phoneNumber)
              &amp;&amp; dbTraineeSsn.equals(csvTraineeSsn) 
              &amp;&amp; this.streetOne.equals(otherTrainee.streetOne)
              &amp;&amp; this.city.equals(otherTrainee.city)
          );
  
          return isEqual;
      }
  
      @Override
      public int hashCode() {
  
          int hash = 37;
          int code = 0;
  
          code = (firstName == null ? 0 : firstName.hashCode());
          hash = hash * 59 + code;
  
          code = (lastName == null ? 0 : lastName.hashCode());
          hash = hash * 59 + code;
  
          code = (email == null ? 0 : email.hashCode());
          hash = hash * 59 + code;
  
          code = (sessionDateTime == null ? 0 : sessionDateTime.hashCode());
          hash = hash * 59 + code;
  
          code = (phoneNumber == null ? 0 : phoneNumber.hashCode());
          hash = hash * 59 + code;
  
          code = (socialSecurityLastFour == null ? 0 : socialSecurityLastFour.hashCode());
          hash = hash * 59 + code;
  
          code = (streetOne == null ? 0 : streetOne.hashCode());
          hash = hash * 59 + code;
  
          code = (city == null ? 0 : city.hashCode());
          hash = hash * 59 + code;
  
          return hash;
  
      }
  }
  </code></pre>
  
  <p><strong>Edit 2 (After overridng hascode() and equals())
  -------------------------------------------------</strong></p>
  
  <p>Found in both:</p>
  
  <pre><code>List&lt;Trainee&gt; foundInBothList1 = dbMonthlyTraineeList.stream()
      .filter(dbTrainee -&gt; csvTraineeList.stream()
          .anyMatch(csvTrainee -&gt; {
              return allBiPredicates.stream().reduce(BiPredicate::and).orElse((x,y)-&gt;true).test(dbTrainee, csvTrainee);
  
          })
      ).collect(Collectors.toList());
  
      List&lt;Trainee&gt; foundInBothList = new ArrayList&lt;&gt;(dbMonthlyTraineeList);
      //foundInBothList.retainAll(new HashSet&lt;&gt;(csvTraineeList));
      foundInBothList.retainAll(csvTraineeList);
  </code></pre>
  
  <p>Found in database but not in CSV</p>
  
  <pre><code>List&lt;Trainee&gt; notInCsvFileList1 = dbMonthlyTraineeList.stream()
      .filter(dbTrainee -&gt; csvTraineeList.stream()
          .noneMatch(csvTrainee -&gt; {
              return allBiPredicates.stream().reduce(BiPredicate::and).orElse((x,y)-&gt;true).test(dbTrainee, csvTrainee);
          })
      ).collect(Collectors.toList());
  
  //find out that elements of dbMonthlyTraineeList which is not present in arraylist(csvTraineeList).
  List&lt;Trainee&gt; notInCsvFileList = new ArrayList&lt;&gt;(dbMonthlyTraineeList);
  notInCsvFileList.removeAll(csvTraineeList);
  </code></pre>