javagenericsfunctional-programmingbounded-wildcard

Applying functions of various types to a value


Let's say I have a method that applies multiple functions to a value.

Example usage:

String value = "a string with numb3r5";
Function<String, List<String>> fn1 = ...
Function<List<String>, String> fn2 = ...
Function<String, List<Integer>> fn3 = ...

InputConverter<String> converter = new InputConverter<>(value);
List<Integer> ints = converter.convertBy(fn1, fn2, fn3);

Is it possible to make it apply multiple functions with various inputs and return values?

I've tried using wildcards, but this doesn't work.

public class InputConverter<T> {
    private final T src;

    public InputConverter(T src) {
        this.src = src;
    }

    public <R> R convertBy(Function<?, ?>... functions) {
        R value = (R) src;

        for (Function<?, ?> function : functions)
            value = (R) function.apply(value);
                                       ^^^^^
        return value;
    }
}

Solution

  • You can use a chain on Function like the following

    Function<String, List<Integer>> functionChain = fn1.andThen(fn2).andThen(fn3);
    

    You can achieve nearly the same thing by using raw types

    @SuppressWarnings({"unchecked", "rawtypes"})
    public <R> R convertBy(Function... functions) {
        Function functionsChain = Function.identity();
    
        for (Function function : functions) {
            functionsChain = functionsChain.andThen(function);
        }
    
        return (R) functionsChain.apply(src);
    }
    

    Otherwise, the only other I see is to use the same pattern as Optional or Stream like suggested in the comments

    List<Integer> fileInputStreams = converter.convertBy(fn1)
            .convertBy(fn2)
            .convertBy(fn3)
            .get();
    
    // with this implementation
    
    public static class InputConverter<T> {
        private final T src;
    
        public InputConverter(T src) {
            this.src = src;
        }
    
        public <R> InputConverter<R> convertBy(Function<T, R> function) {
            return new InputConverter<>(function.apply(src));
        }
    
        public T get() {
            return src;
        }
    }