Работали ли с BigDecimal в Java
Что проверяют
Считали ли вы деньги в реальной системе. Вопрос звучит как приглашение сказать «да, работал», но интервьюер ждёт конкретных граблей: создание из double, сравнение и деление. Следом почти наверняка спросят: «чем new BigDecimal(0.1) отличается от BigDecimal.valueOf(0.1)».
Как отвечать
Начните с причины, а не с методов. double это двоичная дробь, десятичные 0.1 и 0.2 в ней не представимы точно, и на длинной цепочке начислений копейки расходятся. BigDecimal хранит целое значение и масштаб, то есть считает в десятичной системе.
- создание: только
new BigDecimal("10.15")из строки илиBigDecimal.valueOf(double), который идёт черезDouble.toString;new BigDecimal(0.1)даёт точное двоичное значение с хвостом в полсотни знаков; - неизменяемость:
sum.add(item)возвращает новый объект, результат надо присвоить; забытое присваивание это самая частая ошибка в расчётах; - сравнение:
equalsучитывает масштаб, поэтому2.0и2.00не равны, для сравнения значений годится толькоcompareTo(other) == 0. По той же причинеBigDecimalплохой ключ дляHashMap; - деление:
divideбез округления кидаетArithmeticExceptionна бесконечной десятичной дроби, задавайте масштаб иRoundingModeлибоMathContext;HALF_UPпривычен бухгалтерии,HALF_EVENуменьшает системный сдвиг.
Полезно добавить про хранение: в базе numeric(19,4), в JPA точность и масштаб заданы в @Column, в JSON деньги лучше отдавать строкой, иначе клиент прочитает их в double и всё старание пропадёт. Альтернатива: суммы в минорных единицах обычным long или библиотека денежных типов с валютой.
Где спотыкаются
Сравнивают через equals. Сумма из базы приходит с масштабом 2, посчитанная в коде с масштабом 4, условие не срабатывает, а в отладчике оба значения выглядят одинаково.
Создают из double, например new BigDecimal(valueFromJson). Точность потеряна ещё до конструктора, вернуть её нечем, а код выглядит правильным.
Оставляют округление на волю случая. Масштаб и правило это часть бизнес-требования: где округляем, до скольких знаков, по какому правилу. Без этого итог расходится с расчётом бухгалтерии на копейки.