質問
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));
}
}
}
そして、私は、関数呼び出しの数百行を書き出す避けたいと思います。
私は、関数ポインタやファンクタを研究しようとしましたが、適切なものを発見していない。
解決
あなたは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
のための例を - 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));
}
}
他のヒント
Javaは本当に正確にファンクタを行いませんが、インターフェイスを持つ非常に近い得ることができます。私は多分、このような何かをしようとreccommendと思います。
public interface Function {
Object doWork(Object o);
}
public class Function1 implements Function {
public Object doWork(Object o) {
...
}
}
...
そして、あなたのコード内で使用すると、機能1、機能2 ...オブジェクトを含む配列またはリストを作成し、あなたのコードのようにたくさん見える何かを実行したい。
for (Object o : objects) {
for (Function f : functionList) {
f.doWork(o);
}
}
あるいは、入れ子の2つのレベルのために:
for (Object o : objects) {
for (Function f : functionList1) {
for (Function g : functionList2) {
f.doWork(g.doWork(o));
}
}
}
@Seth - ここでは、ジェネリック医薬品とのあなたの例です。ジェネリック医薬品は、実行時に存在していないので、あなたは「柔軟性」の喪失を恐れる理由は、私は理解していません。あなたがジェネリックを使用する場合は、あなただけのオブジェクトを使用しています。
あなたがFの行動は、Gの戻り値の型に基づいて変化するようにしたい場合は、あなただけのFのような何かを行うには、あなたのFを宣言し、簡単peasyます。
//=== 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));
}
}
たぶん、あなたはギャング一緒にこれら聞かせ流れるようなインターフェイスを試すことができます。それは素敵なデザインであるかもしれないが、私はあなたの例から言うことはできません。