13

我只是想知道应用返回的函数的最佳方法VoidIterable/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 中尝试了代码后,我发现我必须将return null语句添加到eatFunction,因为 1)与 2)Void不一样,void并且它是不可实例化的。比想象中的还要丑!:)

同样从性能的角度来看,使用上面的一些复制构造函数调用惰性函数也会毫无意义地分配内存。创建一个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 Consumer 接口。在您的情况下,它将是:

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

正如其他人指出的那样,Guava 团队有一个观点,阻止这样做。如果您正在寻找其他类似函子的 API 来做您想做的事,您可以查看Functional Java 的Effect,或Jedi 的Command,或Play!frameworkF.CallbackCommons Collections4 的Closure[稍后编辑:] 或基于Java 8+Consumer的接口。

于 2012-09-14T17:56:26.560 回答