创建一个方法,接受可变长度的Function参数,可能有不同的类型

时间:2015-10-21 12:42:42

标签: java lambda functional-programming java-8

假设我有一个字符串:String s = "1,2,3,4,5,6"。我想创建一个方法combineFunctions(),它将Function s的可变长度序列作为参数,并按该顺序应用所有操作。

这些功能可能有不同的<T,U>类型。

此类功能的使用示例如下:

Combine<String> c = new Combine<>(s);
List<String> numbers = c.combineFunctions(splitByComma);
Integer max = c.combineFunctions(splitByComma,convertToInt, findMax);

我尝试了什么(这里的<U>没什么用处):

public <U> void combineFunctions(
        Function<? extends Object, ? extends Object>... functions) {

}

但是我被困在获得Function的最后一个类型。我也在考虑递归方法,但varargs参数必须是最后一个。

是否可以在Java中实现这样的方法?

2 个答案:

答案 0 :(得分:3)

这样一个函数的问题是你必须松开所有编译时类型检查并且必须进行转换。

这将是一个实现,使用andThen将功能组合在一起。由于所有的铸造,这看起来很难看,我不确定你能做得更好。另请注意,当只需要1时,这需要创建2个流管道。

public static void main(String[] args) throws Exception {
    String str = "1,2,3,4,5,6";
    Function<Object, Object> splitByComma = s -> ((String) s).split(",");
    Function<Object, Object> convertToInt = tokens -> Stream.of((String[]) tokens).map(Integer::valueOf).toArray(Integer[]::new);
    Function<Object, Object> findMax = ints -> Stream.of((Integer[]) ints).max(Integer::compare).get();
    Integer max = (Integer) combineFunctions(splitByComma, convertToInt, findMax).apply(str);
    System.out.println(max);
}

@SafeVarargs
private static Function<Object, Object> combineFunctions(Function<Object, Object>... functions) {
    return Arrays.stream(functions)
                 .reduce(Function::andThen)
                 .orElseThrow(() -> new IllegalArgumentException("No functions to combine"));
}

要匹配问题中的代码,可以将其包装成如下所示的类:

public class Combiner<R> {

    private Object input;

    public Combiner(Object input) {
        this.input = input;
    }

    @SuppressWarnings("unchecked")
    @SafeVarargs
    public final R combineFunctions(Function<Object, Object>... functions) {
        return (R) Arrays.stream(functions)
                         .reduce(Function::andThen)
                         .orElseThrow(() -> new IllegalArgumentException("No functions to combine"))
                         .apply(input);
    }

}

答案 1 :(得分:3)

使用功能样式Streams可以很容易地解决问题中的示例。 &#34;功能&#34;解决这个问题的方法是使用map个操作序列,每个步骤将元素转换为不同的类型,然后可选地减少/收集结果。

例如

String str = "1,2,3,4,5,6,7";
int max = Arrays.stream(str.split(",")).mapToInt(Integer::parseInt).max().orElse(0)

相同的模式适用于其他类型的&#34;功能组合&#34;。