1

Here is a sample of a code that uses an array int[] instead of an int. All lines containing i are shown in the the code below. This method is executed by several threads.

int[] i = {0}; //So the stream forEach doesn't complain about a potentially final variable to use...
result.forEach (currentOptionRow   -> {
    String bgColor = (0 == i[0] % 2) ? "eaeaea" : "ffffff";

    //Create HTML, use bgColor to generate alternating background
    i[0]++;
});

Is this a workaround to get a mutable counter? Why is it "potentially final"? (There is no final keyword, why is it a concern?)

sixtytrees
  • 1,156
  • 1
  • 10
  • 25
  • 1
    I would just use css to do the alternate colors, see http://stackoverflow.com/questions/3084261/alternate-table-row-color-using-css –  Jun 28 '16 at 15:42
  • See: [this thread](http://stackoverflow.com/a/20938132/2747533). – MirMasej Jun 28 '16 at 15:42
  • I mentioned HTML only to explain the use of this array in the program. I am not trying to change that part either. I haven't seen array counters in places where an `int` should work. My questions are:"Is it really not safe to use `int` in this situation?" and if the answer is "yes", then "What exactly causes the problem?". – sixtytrees Jun 28 '16 at 15:52
  • @MirMasej. Thank you. reading it. – sixtytrees Jun 28 '16 at 15:53
  • 2
    Feel free to comment why you downvote the question. – sixtytrees Jun 28 '16 at 15:53

2 Answers2

3

This is a workaround necessary to deal with lambda requirements. Local variables for lambdas must be final or effectively final.

No, you can't replace it with int if you want to use lambda.

You can change values of elements stored in afinal int[]. That is why you can use it inside of lambda as a counter.

  • I would add that Java lambdas do not [_close over_](https://en.wikipedia.org/wiki/Closure_%28computer_programming%29) free variables. The variable `i` in the lambda is not really the same variable as the `i` in the outer scope. The inner `i` is copied from the outer `i` when the lambda is instantiated, and the fact that both of them are (effectively) immutable sustains the illusion that they are one and the same when they really aren't. – Solomon Slow Jun 28 '16 at 16:14
  • 1
    This is an interesting pattern (more like a dirty hack) that I didn't know about. Thank you for the answer.. – sixtytrees Jun 28 '16 at 16:19
2

Indeed lambdas are somehow evolved anonymous classes so like an anonymous class when you want to use a local variable this variable must be declared as final.

In java 8, they added the notion of effectively final which means that even if it has not been defined explicitly with a final keyword it is still considered as final because it is set only once in the code. This is an improvement that has been added to facilitate the adoption of lambda expressions by the developers as they don't have to pollute their code with final keywords anymore they only need to focus on their lambda expressions.

So indeed you can't use a simple local variable of type int as counter as it cannot be modified but you could use an AtomicInteger or indeed an array as you did.

If you use an anonymous class instead of a lambda, it could be done as next:

result.forEach(new Consumer<String>() {
    int i;
    @Override
    public void accept(final String currentOptionRow) {
        String bgColor = (0 == i % 2) ? "eaeaea" : "ffffff";

        //Create HTML, use bgColor to generate alternating background
        i++;
    }
});
Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122