这样的事情可以用Java做吗?
for (Object o : objects) {
for (Function f : functions) {
f(o);
}
}
我只是在调用一些函数,但我需要编写它们,就像这样:
for (Object o : objects) {
for (Function f : functions) {
for (Function g : functions) {
f(g(o));
}
}
}
我想避免写出数百行函数调用。
我尝试过研究函数指针和仿函数,但没有发现任何相关内容。
答案 0 :(得分:6)
您不能使用f(g(o))
语法,但可以使用(使用合适的界面)f.call(g.call(o))
。
public interface UnaryFunction<Arg, Ret> {
Ret call(Arg arg);
}
示例用法(这与Java中的仿函数一样接近,至少在闭包进入语言之前):
public class Exp implements UnaryFunction<Double, Double> {
public Double call(Double arg) {
return Math.exp(arg);
}
}
如果您不想创建数量众多的类,基于反射的方法可能会更好(double
- &gt; double
java.lang.Math
中的public class MathUnary implements UnaryFunction<Double, Double> {
private final Method method;
public MathUnary(String funName) {
try {
method = Math.class.getMethod(funName, double.class);
} catch (NoSuchMethodException exc) {
throw new IllegalArgumentException(exc);
}
if (method.getReturnType() != double.class)
throw new IllegalArgumentException();
}
public Double call(Double arg) {
try {
return (Double) method.invoke(null, arg);
} catch (IllegalAccessException exc) {
throw new AssertionError(exc);
} catch (InvocationTargetException exc) {
throw new AssertionError(exc);
}
}
}
函数,但很容易适应到其他场景):
MathUnary[] ops = {
new MathUnary("sin"), new MathUnary("cos"), new MathUnary("tan")
};
for (UnaryFunction<Double, Double> op1 : ops) {
for (UnaryFunction<Double, Double> op2 : ops) {
op1.call(op2.call(arg));
}
}
(为简洁起见,省略了异常消息。显然,我会将它们放入生产代码中。)
样本用法:
{{1}}
答案 1 :(得分:0)
也许你可以尝试fluent interface让你将这些团结在一起。这可能是一个很好的设计,但我无法从你的例子中说出来。
答案 2 :(得分:0)
Java并不是真正完美的编写器,但是你可以通过一个接口非常接近。我推荐也许会尝试这样的事情。
public interface Function {
Object doWork(Object o);
}
public class Function1 implements Function {
public Object doWork(Object o) {
...
}
}
...
然后在您的代码中,您将创建一个包含Function1,Function2 ...对象的数组或列表,并运行与您的代码非常相似的内容。
for (Object o : objects) {
for (Function f : functionList) {
f.doWork(o);
}
}
或者,对于两个嵌套级别:
for (Object o : objects) {
for (Function f : functionList1) {
for (Function g : functionList2) {
f.doWork(g.doWork(o));
}
}
}
答案 3 :(得分:0)
@Seth - 这是你的泛型的例子。由于仿制药在运行时不存在,我不明白为什么你担心失去“灵活性”。如果你使用泛型,那么你只是使用对象。
如果你希望F的行为根据G的返回类型而变化,那么你只需要声明你的F做类似F的事情,轻松自如。
//=== Function.java
public interface Function<ReturnType, Type> {
ReturnType doWork(Type arg);
}
//=== SomethingWeird.java
import java.util.*;
// yo dawg, i heard you liked functions. so i put a function in yo'
// function, so you can derive while you derive.
public class SomethingWeird {
public static <FReturnType, FType, GType> List<FReturnType> collateOrSomething(
Iterable<GType> objects,
Iterable<Function<FReturnType, FType>> fList,
Iterable<Function<FType, GType>> gList
) {
List<FReturnType> results = new ArrayList<FReturnType>();
for (GType garg : objects) {
for (Function<FReturnType, FType> f : fList) {
for (Function<FType, GType> g : gList) {
results.add(f.doWork(g.doWork(garg)));
}
}
}
return results;
}
}
//=== SomethingWeirdTest.java
import java.util.*;
import org.junit.*;
import static org.junit.Assert.*;
public class SomethingWeirdTest {
// this is kinda silly, and...
public static class F1 implements Function<Integer, Double> {
@Override
public Integer doWork(Double arg) {
return arg.intValue();
}
}
// ...this has all kinds of autoboxing madness, but...
public static class F2 implements Function<Integer, Double> {
@Override
public Integer doWork(Double arg) {
double ceil = Math.ceil(arg);
return (int) ceil;
}
}
// ...why you'd want to do something like this is quite beyond me...
public static class G1 implements Function<Double, String> {
@Override
public Double doWork(String arg) {
return Math.PI * arg.length();
}
}
// ...ditto this...
public static class G2 implements Function<Double, String> {
@Override
public Double doWork(String arg) {
return Math.E * arg.length();
}
}
// oh, yeah, it was so we could test this weird thing
@Test
public void testCollateOrSomething() {
List<String> data = Arrays.asList("x", "xx", "xxx");
List<Function<Integer, Double>> fList = Arrays.asList(new F1(), new F2());
List<Function<Double, String>> gList = Arrays.asList(new G1(), new G2());
List<Integer> results = SomethingWeird.collateOrSomething(data, fList, gList);
assertEquals(12, results.size());
// x
assertEquals(3, (int) results.get(0));
assertEquals(2, (int) results.get(1));
assertEquals(4, (int) results.get(2));
assertEquals(3, (int) results.get(3));
// xx
assertEquals(6, (int) results.get(4));
assertEquals(5, (int) results.get(5));
assertEquals(7, (int) results.get(6));
assertEquals(6, (int) results.get(7));
// xxx
assertEquals(9, (int) results.get(8));
assertEquals(8, (int) results.get(9));
assertEquals(10, (int) results.get(10));
assertEquals(9, (int) results.get(11));
}
}