流和lambdas作为参数

时间:2017-03-17 07:09:06

标签: lambda java-8 java-stream

我有多个功能可根据条件过滤对象地图。

函数具有相同的主体,只有布尔传递条件才会改变。

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

条件可以来自上层循环的任何对象。 我想将重复的循环代码提取到函数中,但我不知道如何为布尔条件传递某种回调。

谢谢。

1 个答案:

答案 0 :(得分:3)

两种方法的唯一区别是陈述:

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

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

第一个语句不依赖于从内循环获取的myObject,而是依赖于从外循环获取的container。它还取决于传递给方法的参数criterias

第二个语句取决于从内循环和传递给方法的参数myObject获取的criterias

因此,如果您想重构那些产生boolean的语句,您必须找到支持这两种语句的统一方法:

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

现在您已准备好提取这两个语句并将它们作为lambdas传递给您的新方法:

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