質問

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

たぶん、あなたはギャング一緒にこれら聞かせ流れるようなインターフェイスを試すことができます。それは素敵なデザインであるかもしれないが、私はあなたの例から言うことはできません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top