Изменение поведения для возможной потери точности

В Java, когда вы делаете

int b = 0; b = b + 1.0; 

Вы получаете возможную потерю точности ошибки. Но почему это так, если вы

 int b = 0; b += 1.0; 

Нет никакой ошибки?

Это потому, что b += 1.0; эквивалентно b = (int) ((b) + (1.0)); , Сужение примитивного преобразования (JLS 5.1.3) скрыто в операции назначения соединения.

JLS 15.26.2 Операторы соединения (JLS Third Edition):

Составляющее выражение присваивания формы E1 op = E2 эквивалентно E1 = (T) ((E1) op (E2)) , где T – тип E1 , за исключением того, что E1 оценивается только один раз.

Например, следующий код верен:

 short x = 3; x += 4.6; 

и приводит к тому, что x имеет значение 7 потому что оно эквивалентно:

 short x = 3; x = (short)(x + 4.6); 

Это также объясняет, почему следующий код компилируется:

 byte b = 1; int x = 5; b += x; // compiles fine! 

Но это не так:

 byte b = 1; int x = 5; b = b + x; // DOESN'T COMPILE! 

В этом случае необходимо явно указать:

 byte b = 1; int x = 5; b = (byte) (b + x); // now it compiles fine! 

Стоит отметить, что неявный листинг в сложных назначениях является предметом Puzzle 9: Tweedledum из замечательной книги Java Puzzlers . Вот несколько выдержек из книги (слегка отредактированных для краткости):

Многие программисты считают, что x += i; является просто сокращением для x = x + i; , Это не совсем так: если тип результата шире, чем у переменной, оператор составного присваивания выполняет молчащее сужение примитивного преобразования.

Чтобы избежать неприятных сюрпризов, не используйте сложные агенты присваивания для переменных типа byte , short или char . При использовании сложных операторов присваивания для переменных типа int убедитесь, что выражение в правой части не имеет тип long , float или double . При использовании сложных операторов присваивания для переменных типа float убедитесь, что выражение в правой части не имеет тип double . Этим правилам достаточно, чтобы компилятор не создавал опасные сужения.

Для разработчиков языков, вероятно, ошибкой для сложных операторов присваивания создавать невидимые роли; сложные назначения, где переменная имеет более узкий тип, чем результат вычисления, вероятно, должны быть незаконными.

Следует отметить последний абзац: C # в этом отношении является более строгим (см. Спецификацию языка C # 7.13.2 Составное задание ).

Interesting Posts
Давайте будем гением компьютера.