简体   繁体   English

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

[英]Create a method that accepts variable length of Function arguments with possibly different types

Suppose I have a string: String s = "1,2,3,4,5,6" . 假设我有一个字符串: String s = "1,2,3,4,5,6" I would like to create a method combineFunctions() that would take a variable length sequence of Function s as an argument and apply all of the operations in that order. 我想创建一个方法combineFunctions() ,它将Function s的可变长度序列作为参数,并按该顺序应用所有操作。

The functions may have different <T,U> types. 这些函数可能有不同的<T,U>类型。

Example uses of such a function would be the following: 这种功能的示例用法如下:

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

What I have tried (the <U> here is not of much use here): 我试过的(这里的<U>在这里用处不大):

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

}

But I am stuck at getting type of last one of the Function s. 但我坚持要获得Function的最后一个类型。 I was also thinking about a recursive approach but the varargs parameter has to be the last one. 我也在考虑递归方法,但varargs参数必须是最后一个。

Would it be possible to implement such method in Java? 是否可以在Java中实现此类方法?

The problem with such a function is that you loose all compile-time type checking and casting is necessary. 这样一个函数的问题是你必须松开所有编译时类型检查和转换。

This would be an implementation, using andThen to combine functions together. 这将是一个实现,使用和andThen将功能组合在一起。 This looks ugly because of all the casting and I'm not sure you can do it more properly. 由于所有的铸造,这看起来很丑陋,我不确定你能做得更好。 Notice also that this requires the creation of 2 Stream pipelines when only 1 is really necessary. 另请注意,这需要在仅需要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"));
}

To match the code in your question, you could wrap this into a class like this: 要匹配问题中的代码,您可以将其包装成如下所示的类:

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

}

The example in your question is quite easily solved by using the functional-style Streams . 使用功能风格的Streams可以很容易地解决您的问题中的示例。 The "functional" approach to solving this is by using sequences of map operations, each step transforming the elements to a different type, and then optionally reducing/collecting the result. 解决这个问题的“功能”方法是使用map操作序列,每个步骤将元素转换为不同的类型,然后可选地减少/收集结果。

For instance 例如

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

The same pattern would apply for other types of "function combinations". 相同的模式适用于其他类型的“功能组合”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM