BigDecimal вместо Float
Очень часто, в разрабатываемых нами программах реализуется работа с деньгами. Нетрудно догадаться, что отвечающий за это код должен быть хорошо отлажен и защищен от ошибок. Но иногда могут возникнуть такие ошибки, которые заметить очень сложно, а когда они будут замечены - приложение может уже работать у клиента. Одной из таких ошибок является использования класса Float для хранения и проведения операций с финансовой информацией. Эту ошибку часто совершают начинающие разработчики, которые еще не знают, что у класса Float есть проблемы с округлением чисел.
Проведем простой эксперимент:
System.out.println(0.9f - 0.8f);
Можно ожидать, что приведенный код выведет на консоль “0.1″, но на самом деле мы видим “0.099999964″. Это число может быть выведено на страницу счета, что уже плохо. Но самое страшное, что в процессе округления, часть суммы может быть потеряна.
BigDecimal
Класс BigDecimal позволяет производить округление с помощью различных алгоритмов:
RoundingMode:
UP - округление от нуля
DOWN - округление к нулю
CEILING - округление в сторону +∞
FLOOR - округление в сторону -∞
HALF_UP - округление от нуля, если дробная часть >= 0.5
HALF_DOWN - округление от нуля, если дробная часть = 0.5
HALF_EVEN - как и ROUND_HALF_UP, только в случае эквивалентности расстояния
до соседей - округление выполняется в сторону четного числа
UNNECESSARY - округление не производится
Часто, если округление производится в операциях по выплате денег клиентам, используют округление ROUND_DOWN и ROUND_UP для выставления счетов. Для продолжения вычислений с округленным числом используют ROUND_HALF_EVEN, так как этот алгоритм обеспечивает наибольшую точность.
Класс BigDecimal - немодифицируемый, поэтому такие операции как setScale() - возвращают новый объект класса BigDecimal.
Пример округления значения:
System.out.println("UP: " + new BigDecimal(1.5f).setScale(0, RoundingMode.UP));
System.out.println("HALF_UP: " + new BigDecimal(1.5f).setScale(0, RoundingMode.HALF_UP));
System.out.println("HALF_DOWN: " + new BigDecimal(1.5f).setScale(0, RoundingMode.HALF_DOWN));
System.out.println("HALF_EVEN: " + new BigDecimal(1.5f).setScale(0, RoundingMode.HALF_EVEN));
Результаты:
UP: 2 HALF_UP: 2 HALF_DOWN: 1 HALF_EVEN: 2
Но не стоит расслабляться - привденный ниже код также возвращает “0.099999964237213134765625″, как и код, приведенный в начале:
System.out.println(new BigDecimal(0.9f).subtract(new BigDecimal(0.8f)));
Поэтому, если мы считаем копейки, которые должны выставить в счете, необходимо изменить код:
System.out.println(new BigDecimal(0.9f).subtract(new BigDecimal(0.8f)).setScale(2, RoundingMode.UP));
И вот теперь мы можем взять у клиента эти 10 копеек!

Ваш отзыв