Search code examples
javajava-8functional-interface

Java 8 multiple mapping


Is it possible perform multiple mapping on collection? Following code compilation error:

... in Stream cannot be applied to java.util.function.Function<capture<?>,capture<?>>

private static List<?> multipleMapping(final Collection<?> collection, final List<Function<?, ?>> functions) {
    Stream<?> stream = collection.stream();
    for (Function<?, ?> function : functions) {
        stream = stream.map(function);
    }
    return stream.collect(Collectors.toList());
}

I would like to generic solution.


Solution

  • If you have few functions (i.e. if you can write them down), then I suggest you don't add them to a list. Instead, compose them into a single function, and then apply that single function to each element of the given collection.

    Your multipleMapping() method would now receive a single function:

    public static <T, R> List<R> multipleMapping(
        Collection<T> collection, Function<T, R> function) {
    
        return collection.stream()
                .map(function)
                .collect(Collectors.toList());
    }
    

    Then, in the calling code, you could create a function composed of many functions (you will have all the functions anyway) and invoke the multipleMapping() method with that function.

    For example, suppose we have a list of candidates:

    List<String> candidates = Arrays.asList(
            "Hillary", "Donald",
            "Bernie", "Ted", "John");
    

    And four functions:

    Function<String, Integer> f1 = String::length;
    
    Function<Integer, Long> f2 = i -> i * 10_000L;
    
    Function<Long, LocalDate> f3 = LocalDate::ofEpochDay;
    
    Function<LocalDate, Integer> f4 = LocalDate::getYear;
    

    These functions can be used to compose a new function, as follows:

    Function<String, Integer> function = f1.andThen(f2).andThen(f3).andThen(f4);
    

    Or also this way:

    Function<String, Integer> composed = f4.compose(f3).compose(f2).compose(f1);
    

    Now, you can invoke your multipleMapping() method with the list of candidates and the composed function:

    List<Integer> scores = multipleMapping(candidates, function);
    

    So we have transformed our list of candidates into a list of scores, by explicitly composing a new function from four different functions and applying this composed function to each candidate.

    If you want to know who will win the election, you could check which candidate has the highest score, but I will let that as an exercise for whoever is interested in politics ;)