-1

I implemented a Collector for a java 8 stream that will store Entities to a Repository when a given threshold is hit.

public BiConsumer<Tuple2<Integer,List<T>>, T> accumulator() {
    return (tuple, e) -> {
        List<T> list = tuple._2;
        list.add(e);
        if (list.size() >= this.threshold) {
            this.repository.save(list);
            this.repository.flush();
            list = new LinkedList<>();
        }
        tuple = new Tuple2<>(tuple._1 + 1, list);
    };
}

This does not work as intended. The the Element e is added to the list but is not reset after the threshold is reached. Also Integer stays at 0 which is to be expected since its a final member. As it seems my only option is to make my Tuple2 mutable and empty the List :-( Any suggestions how to solve this using immutable tuples?

Christoph Grimmer
  • 4,210
  • 4
  • 40
  • 64
  • 2
    Well, assigning a value to a parameter never has any effect for the caller in Java. That’s called “pass by value” and has been Java’s principle from the very beginning. Why do you expect it to be different in lambda expressions? – Holger Sep 30 '14 at 08:59
  • 1
    That is simply not true. Objects are given to methods by reference. That is the reason why I can modify the content of the Tuple's list from within the function. What does not work (and I now see my error here) is to assign a new object to the reference while expecting to change the external reference, too. – Christoph Grimmer Sep 30 '14 at 09:32
  • 2
    **NO**. *Object references are passed by value*. Please don’t start that old discussion again. When you assign a different reference to the parameter, the caller won’t be affected. The caller will always refer to the same object it referred before, regardless of what the called method did. http://stackoverflow.com/a/40523/2711488 – Holger Sep 30 '14 at 12:21

1 Answers1

1

A lambda expression can be thought of as a function (or method) that simply doesn't have a name. In this example it would be like a method that has two formal parameters tuple and e and also some local variables within its body, including list.

When you make an assignment to a formal parameter or to a local variable, that assignment is local to the current method (or lambda body). No mutation or side effects will be visible to the outside after the accumulator returns, so these assignments won't affect the data structure you're collecting into.

I'm not entirely sure what you're trying to do, but instead of using a tuple (which presumably is immutable and must be replaced instead of mutated) you might try writing an ordinary, mutable class that contains an integer counter (or whatever) and a list. The accumulator would add to the list, conditionally flush and replace the list, and increment the counter. These mutative operations are allowed in collectors because the collector framework carefully thread-confines these operations, so the object you're mutating doesn't need to be thread-safe.

Stuart Marks
  • 127,867
  • 37
  • 205
  • 259