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



假设我有一个字符串: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 s的类型。我还在考虑递归方法,但varargs参数必须是最后一个。

有可能在Java中实现这样的方法吗?

这种函数的问题是,您失去了所有编译时类型检查,并且强制转换是必要的。

这将是一个实现,使用andThen将函数组合在一起。这看起来很丑,因为所有的演员,我不确定你能做得更好。还要注意,这需要创建2个Stream管道,而实际上只需要1个。

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

你的问题中的例子很容易通过使用函数风格的流来解决。解决这个问题的"函数"方法是使用map操作序列,每一步将元素转换为不同的类型,然后选择性地减少/收集结果。

例如

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

同样的模式也适用于其他类型的"函数组合"

最新更新