BigDecimal - использовать new или valueOf - PullRequest
82 голосов
/ 25 августа 2011

Я натолкнулся на два способа получить объект BigDecimal из двойного d.

1. new BigDecimal(d)
2. BigDecimal.valueOf(d)

Какой подход лучше? Будет ли valueOf создавать новый объект?

В общем (не только BigDecimal), что рекомендуется - new или valueOf?

Спасибо.

Ответы [ 3 ]

141 голосов
/ 25 августа 2011

Это два отдельных вопроса: «Что я должен использовать для BigDecimal?» и "Что мне вообще делать?"

Для BigDecimal: это немного сложно, потому что они не делают то же самое . BigDecimal.valueOf(double) будет использовать каноническое String представление значения double, переданного для создания экземпляра объекта BigDecimal. Другими словами: значение объекта BigDecimal будет тем, что вы увидите, когда будете делать System.out.println(d).

Если вы используете new BigDecimal(d), то BigDecimal попытается представить double значение с максимально возможной точностью . Это обычно приведет к тому, что будет сохранено гораздо больше цифр, чем вы хотите. Строго говоря, это более правильно, чем valueOf(), но гораздо менее интуитивно понятно.

В JavaDoc есть хорошее объяснение этого:

Результаты этого конструктора могут быть несколько непредсказуемыми. Можно предположить, что запись new BigDecimal(0.1) в Java создает BigDecimal, который в точности равен 0,1 (немасштабированное значение 1 со шкалой 1), но фактически равен 0,1000000000000000055511151231257827021181583404541015625. Это потому, что 0.1 не может быть представлен точно как double (или, в этом отношении, как двоичная дробь любой конечной длины). Таким образом, значение, которое передается в конструктор, не совсем равно 0,1, несмотря на внешний вид.

Как правило, , если результат тот же (т.е. не в случае BigDecimal, а в большинстве других случаев), тогда предпочтительным является valueOf(): он может выполнять обычное кэширование. значения (как видно на Integer.valueOf()), и это может даже изменить поведение кэширования без необходимости изменения вызывающей стороны. new будет всегда создавать новое значение, даже если в этом нет необходимости (лучший пример: new Boolean(true) против Boolean.valueOf(true)).

41 голосов
/ 15 марта 2012

Если вы используете свои BigDecimal объекты для хранения валютных значений, тогда я настоятельно рекомендую вам НЕ включать любые двойные значения в любом месте своих вычислений.

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

Как только вы пройдете мимо этого, ответ на ваш вопрос прост.Всегда используйте метод конструктора со значением String в качестве аргумента конструктора, так как для String.

нет метода valueOf. Если вы хотите подтверждение, попробуйте следующее:

BigDecimal bd1 = new BigDecimal(0.01);
BigDecimal bd2 = new BigDecimal("0.01");
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);

Вы получите следующий вывод:

bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01

См. Также связанный вопрос

4 голосов
/ 25 августа 2011

В основном valueOf (double val) просто делает это:

return new BigDecimal(Double.toString(val));

Следовательно -> да, будет создан новый объект:).

В общем, я думаю, что это зависит от вашего стиля кодирования. Я не стал бы смешивать valueOf и «new», если бы оба результата были одинаковыми.

...