假设我有一个字符串: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)
同样的模式也适用于其他类型的"函数组合"