1

私は最近 Scala で働き始めましたが、それが関数型パラダイムとの最初の接触でした。私は Java の大ファンですが、認めますが、Java には機能的なパラダイムが欠けていることがあります。

そういうわけで、私は最近、ミニペットプロジェクトを開始して、そのようなことが Java である程度達成できるかどうかを確認しました。

配列リストの簡単な変更から始めました。これがこれまでの結果です。


要素に関数を適用するためにコレクションが実装する必要があるインターフェイス:

public interface Functionalizable<E> {
    public Collection<E> apply(Function<E> f);
}

単一の要素に関数を適用するためのメソッドを定義するインターフェイス:

public interface Function<E> {
    public E apply(E e);
}

要素に関数を適用できる配列リストに基づく具象クラス:

public class FunctionArrayList<E> implements List<E>, Functionalizable<E> {
    private List<E> list;

    //implemented methods from `List` interface and ctors

    @Override
    public List<E> apply(Function<E> f) {

        List<E> applied = new FunctionArrayList<>(this.list.size());

        for (E e : this.list) {
            applied.add(f.apply(e));
        }

        return applied;
    }
}

Integer の小さなテスト メソッドを作成しましたが、問題なく動作します。

コード:

    List<Integer> listOfIntegersBefore = new FunctionArrayList<>();
    listOfIntegersBefore.add(-1);
    listOfIntegersBefore.add(0);
    listOfIntegersBefore.add(1);
    listOfIntegersBefore.add(2);
    listOfIntegersBefore.add(3);
    listOfIntegersBefore.add(4);

    System.out.println("Before<Integer>: " + listOfIntegersBefore.toString());

    List<Integer> listOfIntegersAfter = ((FunctionArrayList<Integer>) listOfIntegersBefore).apply(new Function<Integer>() {

        @Override
        public Integer apply(Integer e) {
            return (e + 1);
        }
    });

    System.out.println("After<Integer> : " + listOfIntegersAfter.toString());

出力:

Before<Integer>: [-1, 0, 1, 2, 3, 4]
After<Integer> : [0, 1, 2, 3, 4, 5]

しかし、List でもう少し複雑なことをしようとすると、好きではない多くの型キャストになってしまいます (できるだけ避けたいと思います)。
コード:

    List<List<Integer>> listOfListOfIntegersBefore = new FunctionArrayList<>();

    List<Integer> temp = new FunctionArrayList<>();
    temp.add(1);
    listOfListOfIntegersBefore.add(temp);

    temp = new FunctionArrayList<>();
    temp.add(1);
    temp.add(2);
    listOfListOfIntegersBefore.add(temp);

    temp = new FunctionArrayList<>();
    temp.add(1);
    temp.add(2);
    temp.add(3);
    listOfListOfIntegersBefore.add(temp);

    temp = new FunctionArrayList<>();
    temp.add(1);
    temp.add(2);
    temp.add(3);
    temp.add(4);
    listOfListOfIntegersBefore.add(temp);

    List<List<Integer>> listOfListOfIntegersAfter = (List<List<Integer>>) ((Functionalizable<List<Integer>>) listOfListOfIntegersBefore).apply(new Function<List<Integer>>() {

        @Override
        public List<Integer> apply(List<Integer> e) {
            List<Integer> list = new FunctionArrayList<>(e);

            return ((FunctionArrayList<Integer>) list).apply(new Function<Integer>() {

                @Override
                public Integer apply(Integer e) {
                    return (e + 1);
                }
            });
        }
    });
    System.out.println("Before<List<Integer>>: " + listOfListOfIntegersBefore);
    System.out.println("After<List<Integer>> : " + listOfListOfIntegersAfter);

出力:

Before<List<Integer>>: [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
After<List<Integer>> : [[2], [2, 3], [2, 3, 4], [2, 3, 4, 5]]

すでに述べたように、キャストは避けたいと思います。Type safety: Unchecked cast from List<List<Integer>> to Functionalizable<List<Integer>>さらに、Eclipseは次の行について警告します。

List<List<Integer>> listOfListOfIntegersAfter = (List<List<Integer>>) ((Functionalizable<List<Integer>>) listOfListOfIntegersBefore).apply(new Function<List<Integer>>() {
    ...
}

それを達成するエレガントな方法はありますか?

4

2 に答える 2

2

あなたは自分の人生を苦しめています。

List<List<Integer>> listOfListOfIntegersBefore = new FunctionArrayList<>();
[...]
((FunctionArrayList<Integer>) listOfIntegersBefore).apply

そもそも保管しないのはなぜFunctionArrayListですか?もちろん、このようにキャストする必要があります。

とにかく、各リストを関数リストでラップするのは少し面倒だと思います。単純な静的メソッドでそれを行いたいと思います。

public interface F<S, T> { T apply(S s); }


public final class FunctionalStuff {
  private FunctionalStuff() {}


  public <S, T> static List<T> map(Collection<? extends S> collection,
                                   F<? super S, ? extends T> func) {
    final List<T> result = new ArrayList<T>(collection.size()); 
    for (S source : collection)
      result.add(func.apply(source)); 
    return result;
  }


  public <S, T> static List<S> filter(Collection<? extends S> collection,
                                      F<? super S, Boolean> predicate) {
    final List<T> result = new ArrayList<T>(collection.size()); 
    for (S source : collection)
      if (predicate.apply(source))
        result.add(source); 
    return result; 
  }

  // etc etc.
}

とにかく、注意してください: Java で関数型のコーディングを行うことはお勧めしません。Java 8 で追加されるクロージャを待ちます。

あるいは、関数型スタイルを取り入れた言語を使用してください: Scala、Javascript、Clojure、Lisp、Mathematica など、たくさんあります! これに関しては、c(++) でさえ Java よりも煩わしくないようです。

于 2012-07-14T14:03:57.890 に答える
0

多分あなたはop4jをチェックアウトしたいでしょう。彼らはあなたが達成したいことを非常にきちんとした方法で行ったと思います. ソースを見てそこから学ぶか、単純にライブラリを使用してください。

于 2012-07-14T14:20:54.207 に答える