13

?に戻る関数を適用するための最良の方法は何Voidでしょうか。Iterable/Collection

私のユースケースは次のとおりです。

  • Animalオブジェクトのリストがあります
  • リストの各動物にeat()関数を呼び出したい

Function<Animal,Void>input.eat();

私が電話すると、次のことがわかります。

Collections2.transform(animalList,eatFunction);

私は変換を探しているのではなく、出力のないアプリケーションのみを探しているので、これは非常にエレガントだとは思いません。最悪の場合、Guava変換がビューを返しているため、機能しません。

正常に機能するのは次のとおりです。

Lists.newArrayList( Collections2.transform(animalList,eatFunction) );

しかし、それはエレガントではありません。Guavaを使用して機能的に、Void関数をIterable / Collectionに適用する最良の方法は何ですか?

編集

4

3 に答える 3

28

何がよりエレガントだと思いますか?昔ながらのforループ:

for (Animal animal : animalList)
    animal.eat();

または「関数型の手続き型操作を書くことによって手続き型言語を曲げる」狂気?

static final Function<Animal, Void> eatFunction = new Function<Animal, Void>() {
    @Override
    public Void apply(Animal animal) {
        animal.eat();
        return null; // ugly as hell, but necessary to compile
    }
}

Lists.newArrayList(Collections2.transform(animalList, eatFunction));

私は最初のケースに投票します。

プログラムを機能的なスタイルで作成したい場合は、別のJVM言語に切り替えることをお勧めします。

Scalaはそのような場合の良い代替手段かもしれません:

animalList.foreach(animal => animal.eat)

または、_プレースホルダーを使用したより短いバリアント:

animalList.foreach(_.eat)

編集:

Eclipseでコードを試した後、1)はと同じではなく、2)インスタンス化できないため、return nullステートメントをに追加する必要があることがわかりました。それは予想よりもさらに醜いです!:)eatFunctionVoidvoid

また、パフォーマンスの観点から、上記のようなコピーコンストラクターを使用してレイジー関数を呼び出すと、メモリが無意味に割り当てられます。nullのみで埋められたArrayListものと同じサイズanimalListが作成され、すぐにガベージコレクションされます。

いくつかの関数オブジェクトを渡し、それらをいくつかのコレクションに動的に適用したいというユースケースがある場合は、独自の関数型インターフェイスとforeachメソッドを作成します。

public interface Block<T> {
    void apply(T input);
}

public class FunctionUtils {
    public static <T> void forEach(Iterable<? extends T> iterable,
            Block<? super T> block) {
        for (T element : iterable) {
            block.apply(element);
        }
    }

}

void次に、同様に(小文字の)関数を定義できます。

static final Block<Animal> eatFunction = new Block<Animal>() {
    @Override
    public void apply(Animal animal) {
        animal.eat();
    }
};

そして、次のように使用します。

FunctionUtils.forEach(animalList, eatFunction);
// or with a static import:
forEach(animalList, eatFunction);
于 2012-09-14T18:20:03.217 に答える
7

私は同じものを探していて、Javaコンシューマーインターフェイスを見つけました。あなたの場合は次のようになります。

final Consumer<Animal> action = new Consumer<Animal>() {
    @Override
    public void accept(Animal animal) {
        animal.eat();
    }
};    
...
FluentIterable.from(animals).forEach(action);
于 2015-08-26T08:54:14.250 に答える
5

他の人が指摘したように、グアバチームはこれを行うことを妨げる視点を持っています。やりたいことを実行するための他のファンクターのようなAPIを探している場合は、Functional JavaEffect、またはJediのCommandクラス、またはPlayをチェックしてください。フレームワークF.Callback、またはCommons Collections4のClosure[後で編集:]またはJava8+Consumerベースのインターフェース。

于 2012-09-14T17:56:26.560 に答える