Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 912
Artur Avatar asked Mar 18 '16 23:03

Artur


People also ask

Can Java 8 have multiple maps?

Now, you can invoke your multipleMapping() method with the list of candidates and the composed function : List<Integer> scores = multipleMapping(candidates, function);

What does .stream do in Java?

Introduced in Java 8, the Stream API is used to process collections of objects. A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result. A stream is not a data structure instead it takes input from the Collections, Arrays or I/O channels.

What is a flatMap in Java 8?

In Java 8 Streams, the flatMap() method applies operation as a mapper function and provides a stream of element values. It means that in each iteration of each element the map() method creates a separate new stream. By using the flattening mechanism, it merges all streams into a single resultant stream.

What is difference between MAP and flatMap?

map() function produces one output for one input value, whereas flatMap() function produces an arbitrary no of values as output (ie zero or more than zero) for each input value.


1 Answers

The problem comes from the fact that you're using a generic wildcard ?. What you want is to have a parameterized type T, that will represent the type of the Stream element. Assuming the function would return the same type as their input, you could have:

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

This compiles fine: the mapper given to map correcly accepts a T and returns a T. However, if the functions don't return the same type as their input then you won't be able to keep type-safety and will have to resort to using List<Function<Object, Object>>.


Note that we could use a UnaryOperator<T> instead of Function<T, T>.

Also, you could avoid the for loop and reduce all functions into a single one using andThen:

private static <T> List<T> multipleMapping(final Collection<T> collection, final List<Function<T, T>> functions) {
    return collection.stream()
                     .map(functions.stream().reduce(Function.identity(), Function::andThen))
                     .collect(Collectors.toList());
}
like image 149
Tunaki Avatar answered Oct 31 '22 01:10

Tunaki