The rule about not being able to assign to final variables more than once, written more formally (JLS 4.12.4):
It is a compile-time error if a final variable is assigned to unless it is definitely unassigned immediately prior to the assignment.
The Java Language Specification spends the whole chapter 16 talking about what counts as "definitely assigned" and "definitely unassigned". A variable can be either "definitely assigned" or "definitely unassigned", both, or neither.
In this case, if you apply the rules about for loops on your code, you will see that there is only one rule that talks about the definite [un]assignment after for loop:
Let's try to show that str is definitely unassigned after the for loop.
In a enchanted for loop, there is obviously a condition expression (checks if the iterator hasNext). The condition doesn't involve str, so str stays unassigned as before. We meet the first bullet point. str is assigned before the break though, so we don't meet the second bullet point.
We cannot show that str is definitely unassigned after the for loop using the rules in chapter 16. (In fact we can't show it is assigned after the for loop either, but that's rather irrelevant.) The if (!found) statement isn't doing any assignment either, so this means that str is not definitely unassigned before str = "none";. Hence the compiler error according to 4.12.4.
If you still want to use a final variable, Try using a basic for loop to get the index of the found element, then assign it to str:
final List<Long> idList = List.of(1L,2L,3L);
final String str;
int index = -1;
for (int i = 0; i < idList.size(); i++) {
Long id = idList.get(i);
if (id == 2) {
index = i;
break;
}
}
if (index < 0) {
str = "none";
} else {
str = "id" + idList.get(index);
}
Alternatively, use streams:
final String str =
idList.stream()
.filter(x -> x == 2)
.findFirst()
.map(x -> "id" + x)
.orElse("none");
strwas assigned multiple times. Note that even though your code seems to be simple enough to grasp on a glance the compiler would have to be able to handle much more complex situations which could take a while and still be wrong. So it has to draw a line somewhere ... and your code already crosses it. - Thomas