1

Given a value foo and a Stream of Consumer<Foo> void functions, what's the most concise way to apply each function to the value? Right now I have

consumers.forEach(c -> c.accept(foo));

which isn't terrible, but I suspect there might be some way to turn this inside out and do it with just method references (no explicit lambda). Possibly something with a singleton list and zip()?

I'd be happy with a straight Java 8 answer, or Vavr, or Scala.

(Note that this is not a fold, or at least not the usual foldLeft/foldRight application; if there were return values, I'd be discarding them, not iterating on them.)

David Moles
  • 48,006
  • 27
  • 136
  • 235
  • Is *concatenating* via [`Consumer#andThen(Consumer after)`](https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html#andThen-java.util.function.Consumer-) a valid option? – Izruo Nov 28 '17 at 22:02
  • Interesting question but in Java there is nothing as simple, concise, or performant in typical VMs, than what you already have. – Lucas Ross Nov 28 '17 at 22:20
  • `forEach` and void functions aren't used in functional idioms ... you're looking for something that doesn't exist – Mulan Nov 29 '17 at 15:40
  • @naomik OK, pretend it's `functions.map(f -> f.apply(foo))` if you find that less nonexistent. – David Moles Nov 29 '17 at 17:40
  • @naomik And consider the IO monad. – David Moles Nov 29 '17 at 17:42
  • @DavidMoles `map` will build a new collection, which can be sent to another function; `forEach` does not have a return value and therefore cannot be composed – `forEach` and void functions are not functional – Mulan Nov 29 '17 at 17:43
  • @naomik I know what `map` does. – David Moles Nov 29 '17 at 17:48
  • so then you’ll stop comparing it to `forEach` as some sort of equivalent? – Mulan Nov 29 '17 at 17:49
  • @naomik The functionality of `map()` is a strict superset of `forEach()`. I would be happy with a solution that uses `map()`. – David Moles Nov 29 '17 at 18:03

3 Answers3

1

I think the real concern here is that methods which return void are a code smell. Why couldn't they return something useful, or at least carry out their side-effect and then return the original value, which allows for better chaining. I think that would be a preferable approach, but short of that, I think the forEach approach is ok.

  • Would that make the code more concise? Say I (somewhere else, so it doesn't count against the concision) wrapped each `Consumer` as a `Function`: `Stream> functions = consumers.map(c -> (f) -> { c.accept(f); return f; });` — what would be the concise way to chain those? – David Moles May 01 '18 at 17:49
0

You could reduce your consumers by means of the Consumer.andThen method and then apply the resulting consumer to the foo argument:

consumers.reduce(Consumer::andThen).ifPresent(c -> c.accept(foo));

But there's no difference between this approach and yours, and yours' is shorter.

fps
  • 33,623
  • 8
  • 55
  • 110
0

In Scala you should be able to do

consumers.foreach(_.accept(foo));
haaawk
  • 330
  • 1
  • 8
  • 2
    That's exactly what the OP _did_, it's right there in the question. – jwvh Nov 28 '17 at 22:40
  • It's not exactly the same. It compiles to the same bytecode but using different syntax. I'm not saying this is revolutionary but David asked for the way to do it in a more concise way and this is shorter, isn't it? – haaawk Nov 29 '17 at 07:07
  • True enough, but if you are really trying to achieve concise Scala you would use `foreach` (`forEach` isn't Scala) and you'd drop the semicolon `;` (Scala isn't Java). Even after that, if we were playing a round of [code golf](https://en.wikipedia.org/wiki/Code_golf), I'd still have you beat by 2 strokes: `for(c<-consumers)c.accept(foo)` – jwvh Nov 29 '17 at 08:06
  • Yeah. I could get a bit closer with `consumers.foreach(_ accept foo)`. Still one character behind :). `consumers foreach _ accept foo` probably won't work :). – haaawk Nov 29 '17 at 12:38
  • The reason I suggested I'd take a Scala solution is that it's usually straightforward to translate from Scala to Vavr, and there are probably more Scala programmers on here than (good) functional Java programmers. This answer is "more concise," but only because Scala is more concise. – David Moles Nov 29 '17 at 17:51