2017-03-17 3 views
2

Ich habe mehrere Funktionen, um eine Karte von Objekten anhand von Kriterien zu filtern.Stream und Lambdas als Parameter

Funktionen haben den gleichen Körper, nur die boolesche Passbedingung ändert sich.

filterOnFirstCriteria(Criteria criterias, Map<Integer, List<Container>> containerMap, Map<Integer, ClassKey> classKeys) { 
     for (Map.Entry<Integer, List<Container>> entry : containerMap.entrySet()) { 
      List<Container> containers = entry.getValue(); 
      ClassKey classKey = classKeys.get(entry.getKey()); 
      for (Container container : containers) { 
       List<MyObject> found = new ArrayList<>(); 
       for (MyObject myObject : container.getMyObjects()) { 
        boolean pass = criterias.getListOfFilter().stream().filter(s -> s.equals(container.getReference())).count() > 0; 
        if (pass) { 
         found.add(myObject); 
        } 
       } 
       container.getMyObjects().removeAll(found); 
      } 
     } 
    } 


filterOnOtherCriteria(Criteria criterias, Map<Integer, List<Container>> containerMap, Map<Integer, ClassKey> classKeys) { 
     for (Map.Entry<Integer, List<Container>> entry : containerMap.entrySet()) { 
      List<Container> containers = entry.getValue(); 
      ClassKey classKey = classKeys.get(entry.getKey()); 
      for (Container container : containers) { 
       List<MyObject> found = new ArrayList<>(); 
       for (MyObject myObject : container.getMyObjects()) { 
        boolean pass = myObject.getListOfObject().stream().filter(obj -> criterias.getLocations().stream().anyMatch(location -> location.equals(obj.getLocation()))).count() > 0; 
        if (pass) { 
         found.add(myObject); 
        } 
       } 
       container.getMyObjects().removeAll(found); 
      } 
     } 
    } 

Bedingungen können auf alle Objekte von oberen Schleifen sein. Ich möchte den duplizierten Schleifencode in eine Funktion extrahieren, aber ich weiß nicht, wie ich eine Art Callback für die boolesche Bedingung übergeben soll.

Vielen Dank.

+3

Pass ein zusätzliches Prädikats , wo Kontext all notwendigen Informationen für das Prädikat zurückgeben wahr oder falsch (dh myObject, Container, Kriterien sollten, zu entscheiden, enthalten würde s). –

Antwort

3

Der einzige Unterschied bei beiden Verfahren sind die Aussagen:

boolean pass = criterias.getListOfFilter().stream() 
    .filter(s -> s.equals(container.getReference())) 
    .count() > 0; 

und

boolean pass = myObject.getListOfObject().stream() 
    .filter(obj -> criterias.getLocations().stream() 
      .anyMatch(location -> location.equals(obj.getLocation()))) 
    .count() > 0; 

Die erste Anweisung nicht auf myObject abhängt abgerufen von der inneren Schleife, sondern auf container geholten von der äußeren Schleife . Dies hängt auch von dem Parameter criterias ab, der an die Methode übergeben wird.

Die zweite Anweisung hängt von myObject ab, die aus der inneren Schleife abgerufen wird, und vom Parameter criterias, der an die Methode übergeben wird.

Also, wenn Sie diese Aussagen Refactoring wollen, die die boolean produzieren, müssen Sie beide Aussagen ein einheitliches Verfahren finden Unterstützung wie:

@FunctionalInterface 
public interface Guardian { 
    boolean pass(MyObject myObject, Container container); 
} 

Nun sind Sie bereit, diese beiden Aussagen zu extrahieren und sie passieren auf Ihre neue Methode als Lambda-Ausdrücke:

public static void filterOnFirstCriteria(Criteria criterias, Map<Integer, List<Container>> containerMap, Map<Integer, ClassKey> classKeys) { 
    filterOn(criterias, containerMap, classKeys, (myObject, container) -> 
     criterias.getListOfFilter().stream() 
            .filter(s -> s.equals(container.getReference())) 
            .count() > 0); 
} 

public static void filterOnOtherCriteria(Criteria criterias, Map<Integer, List<Container>> containerMap, Map<Integer, ClassKey> classKeys) { 
    filterOn(criterias, containerMap, classKeys, (myObject, container) -> 
     myObject.getListOfObject().stream() 
            .filter(obj -> criterias.getLocations().stream().anyMatch(location -> location.equals(obj.getLocation()))) 
            .count() > 0); 
} 

public static void filterOn(Criteria criterias, Map<Integer, List<Container>> containerMap, Map<Integer, ClassKey> classKeys, Guardian guardian) { 
    for (Map.Entry<Integer, List<Container>> entry : containerMap.entrySet()) { 
     List<Container> containers = entry.getValue(); 
     ClassKey classKey = classKeys.get(entry.getKey()); 
     for (Container container : containers) { 
      List<MyObject> found = new ArrayList<>(); 
      for (MyObject myObject : container.getMyObjects()) { 
       if (guardian.pass(myObject, container)) { 
        found.add(myObject); 
       } 
      } 
      container.getMyObjects().removeAll(found); 
     } 
    } 
}