Is there any way to use BiConsumers as simply as Consumers?

时间:2015-06-25 09:59:00

标签: java java-8 method-reference

This is just a theorical question with no concrete application.

I have the following method which I will not touch. It could (if possible at all) be used as a BiConsumer.

void doSmallThing(A a, B b) {
  // do something with a and b.
}

void doBigThing(List<A> as, B b) {
  // What to do?
}

How can I iterate on as while keeping b constant and use this::doSmallThing in doBigThing?

Of course the following doesn't work.

void doBigThing(List<A> as, B b) {
  as.stream()
  .forEach(this::doSmallThing);
}

The following works nice and is actually what I use everyday.

void doBigThing(List<A> as, B b) {
  as.stream()
  .forEach(a -> doSmallThing(a, b));
}

The following also works well, but is a bit more tricky.

Consumer<A> doSmallThingWithFixedB(B b) {
  return (a) -> doSmallThing(a, b);
}

void doBigThing(List<A> as, B b) {
  as.stream()
  .forEach(doSmallThingWithFixedB(b))
}

But all of those solutions don't get the simplicity of the Consumer case. So is there anything simple that exists for BiConsumer?

3 个答案:

答案 0 :(得分:7)

你想&#34;绑定&#34;函数参数。遗憾的是,在Java 8中没有内置机制来执行此操作(除了绑定对象,例如this::之类的方法)。您可以像这样推广doSmallThingWithFixedB方法:

public class Bind {
    public static <A, B> Consumer<A> bindLast(BiConsumer<A, B> fn, B b) {
        return a -> fn.accept(a, b);
    }

    public static <A, B> Consumer<B> bindFirst(BiConsumer<A, B> fn, A a) {
        return b -> fn.accept(a, b);
    }
}

并使用:

void doBigThing(List<A> as, B b) {
  as.stream()
    .forEach(Bind.bindLast(this::doSmallThing, b));
}

可能有一些已经包含此类方法的第三方库。但是使用显式lambda对我来说似乎没问题。你不应试图用方法参考来表达所有内容。

答案 1 :(得分:1)

在迭代Map条目时使用BiConsumers,例如:

Map<A, B> map = ...;
map.forEach(this::doSomething);

Stream.collect()也将BiConsumers作为参数,但它的使用频率低于对地图条目的迭代次数。

答案 2 :(得分:0)

将方法doSmallThing添加到B:

class B {
    public void doSmallThing(A a) {
         YourClass.doSmallThing(a, this); // You may want to inline this.
    }
}

并从doBigThing

调用它
void doBigThing(List<A> as, B b) {
    as.stream()
        .forEach(b::doSmallThing);
}