Это ошибка в javac
, начиная с JDK 9 (которая внесла некоторые изменения в отношении конкатенации строк, что, как я подозреваю, является частью проблемы), , как подтверждено командой javac
под этой ошибкойid JDK-8204322 .Если вы посмотрите на соответствующий байт-код для строки:
array[i++%size] += i + " ";
Это:
21: aload_2
22: iload_3
23: iinc 3, 1
26: iload_1
27: irem
28: aload_2
29: iload_3
30: iinc 3, 1
33: iload_1
34: irem
35: aaload
36: iload_3
37: invokedynamic #5, 0 // makeConcatWithConstants:(Ljava/lang/String;I)Ljava/lang/String;
42: aastore
Где последний aaload
- фактическая загрузка из массива.Однако часть
21: aload_2 // load the array reference
22: iload_3 // load 'i'
23: iinc 3, 1 // increment 'i' (doesn't affect the loaded value)
26: iload_1 // load 'size'
27: irem // compute the remainder
, которая примерно соответствует выражению array[i++%size]
(минус фактическая загрузка и сохранение), находится там дважды.Это неверно, как сказано в спецификации в jls-15.26.2 :
Составное выражение присваивания в форме E1 op= E2
эквивалентно E1 = (T) ((E1) op (E2))
, где T
это тип E1
, , за исключением того, что E1
вычисляется только один раз.
Таким образом, для выражения array[i++%size] += i + " ";
часть array[i++%size]
должна толькооцениваться один раз.Но он оценивается дважды (один раз для загрузки и один раз для магазина).
Так что да, это ошибка.
Некоторые обновления:
Ошибка исправлена в JDK 11, и будет обратный порт к JDK 10 (но не JDK 9, поскольку больше не получает публичные обновления ).
Алексей Шипилев упоминает на странице JBS (и @DidierL в комментариях здесь):
Обходной путь: компилировать с -XDstringConcat=inline
Thatвернется к использованию StringBuilder
для конкатенации и не будет иметь ошибки.