_Iterable/Collection
_にVoid
を返す関数を適用する最良の方法は何でしょうか?
私のユースケースは次のとおりです。
Animal
オブジェクトのリストがありますeat()
関数を呼び出したいinput.eat();
を呼び出す_Function<Animal,Void>
_があります
私が電話すると、次のことがわかります。
_Collections2.transform(animalList,eatFunction);
_
私は変換を探しているのではなく、出力のないアプリケーションのみを探しているので、これは非常にエレガントだとは思いません。最悪の場合、グアバ変換がビューを返しているため、機能しません。
正常に機能するのは次のとおりです。
_Lists.newArrayList( Collections2.transform(animalList,eatFunction) );
_
しかし、それはエレガントではありません。 Guavaを使用して機能的に、Void関数を反復可能/コレクションに適用する最良の方法は何ですか?
編集:
何がよりエレガントだと思いますか?昔ながらの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)eatFunction
はVoid
と同じではなく、2)インスタンス化できないため、return null
ステートメントをvoid
に追加する必要があることがわかりました。それは予想よりもさらに醜いです! :)
また、パフォーマンスの観点から、上記のようなコピーコンストラクターを使用してレイジー関数を呼び出すと、メモリが無意味に割り当てられます。 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);
私はちょうど同じものを探していて、Javaコンシューマーインターフェイスを見つけました。あなたの場合は次のようになります:
final Consumer<Animal> action = new Consumer<Animal>() {
@Override
public void accept(Animal animal) {
animal.eat();
}
};
...
FluentIterable.from(animals).forEach(action);
他の人が指摘したように、グアバチームはこれを行うことを妨げる視点を持っています。やりたいことを実行するための他のファンクターのようなAPIを探している場合は、 関数型JavaのEffect
、または ジェダイのCommand
クラス 、または Play!フレームワークのF.Callback
、または CommonsCollections4のClosure
[後で編集:]または Java 8+ Consumer
ベースのインターフェース。