Тихий убийца Java - целочисленное переполнение, осторожно!
Хотите верьте, хотите нет, но в Java есть и целочисленное переполнение буфера. Не уверен, что это правильное слово, чтобы описать это или нет, может быть, вы можете предложить некоторые :)
Хорошо, пожалуйста, взгляните на программу ниже, эта программа выводит количество микросекунд в день.
public class JavaLongOverflow { public static void main(String[] args) { final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000; System.out.println("MICROS_PER_DAY : " + MICROS_PER_DAY); } }
Результат
MICROS_PER_DAY : 500654080
Oh.. ответ:500654080. Подождите.. правильный ответ? Правильный ответ должен быть86400000000 !!! Почему Java дает неточный результат? откуда этот номер? Что именно произошло?
Я считаю, что это вызвано переполнением int. Да, переменная long MICROS_PER_DAY имеет достаточно места, чтобы поместиться в большое число, например 86400000000, но она не подходит для int! Максимальное количество int - 2147483647. Внимательно посмотрите на программу выше, вся арифметика ведется в «int», результат повышается до long и присваивается переменной «long MICROS_PER_DAY». According to [JLS 5.1.2], the promotion from int to long is cited as widening primitive conversion which preserves the (incorrect) numerical value.
Однако мы можем избежать вышеупомянутого тихого убийственного переполнения, явно указав «длинное» в первом целом числе, чтобы вся операция превратилась в длинную арифметику.
public class JavaLongOverflow { public static void main(String[] args) { final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000; System.out.println("MICROS_PER_DAY : " + MICROS_PER_DAY); } }
Результат
MICROS_PER_DAY : 86400000000
Выше программа печатает 86400000000, как и ожидалось
Заключение
Эту ошибку так сложно обнаружить или узнать. Иногда это даже невозможно обнаружить. Если кто-то совершит такую ошибку в финансовой системе, я просто не могу представить себе ее последствия. Мой единственный совет - явно приводить примитивный тип при вычислении двух разных типов примитивного типа. Всегда избегайте автоматического расширения примитивного преобразования в любых вычислениях.