我只是想知道在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的最佳方法是什么?
修改:
答案 0 :(得分:27)
您认为更优雅的是什么?一个普通的旧循环:
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语言,而不是对名叫Java的老太太强奸。 :)
对于这种情况,Scala 可能是一个不错的选择:
animalList.foreach(animal => animal.eat)
甚至是使用_
占位符的较短变体:
animalList.foreach(_.eat)
在Eclipse中尝试代码之后,我发现我必须将return null
语句添加到eatFunction
,因为1)Void
与void
不同和2)它是不可实现的。那比预期的更难看! :)
同样从性能的角度来看,使用上面的一些复制构造函数调用惰性函数也毫无意义地分配了内存。创建与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);
答案 1 :(得分:5)
正如其他人所指出的那样,番石榴团队的观点不允许这样做。如果您正在寻找其他类似仿函数的API,您可以查看Functional Java's Effect
或Jedi's Command
class,Play! framework's F.Callback
或Commons Collections4's Closure
[稍后修改:基于Java 8+ Consumer
的接口。