DecimalFormat и Double.valueOf () - PullRequest
       60

DecimalFormat и Double.valueOf ()

13 голосов
/ 22 апреля 2010

Я пытаюсь избавиться от ненужных символов после десятичного разделителя моего двойного значения. Я делаю это так:

DecimalFormat format = new DecimalFormat("#.#####");
value = Double.valueOf(format.format(41251.50000000012343));

Но когда я запускаю этот код, он выдает:

java.lang.NumberFormatException: For input string: "41251,5"
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224)
    at java.lang.Double.valueOf(Double.java:447)
    at ...

Как я вижу, Double.valueOf() прекрасно работает с такими строками, как "11.1", но он задыхается от таких строк, как "11,1" Как мне обойти это? Есть ли более элегантный способ, чем-то вроде

Double.valueOf(format.format(41251.50000000012343).replaceAll(",", "."));

Есть ли способ переопределить значение десятичного разделителя по умолчанию для класса DecimalFormat? Есть еще мысли?

Ответы [ 10 ]

76 голосов
/ 22 апреля 2010

По

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

Вы действительно имеете в виду, что хотите округлить, например, до 5-й знак? Тогда просто используйте

value = Math.round(value*1e5)/1e5;

(конечно, вы также можете Math.floor(value*1e5)/1e5, если вы действительно хотите, чтобы другие цифры были обрезаны)

25 голосов
/ 22 апреля 2010

Проблема в том, что ваш десятичный формат преобразует ваше значение в локализованную строку.Я предполагаю, что ваш десятичный разделитель по умолчанию для вашей локали с ','.Это часто случается с французскими локалями или другими частями мира.

По сути, вам нужно создать отформатированную дату с помощью '.'разделитель, чтобы Double.valueOf мог прочитать его.Как указано в комментариях, вы также можете использовать тот же формат для анализа значения вместо использования Double.valueOf.

DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
symbols.setDecimalSeparator('.');
DecimalFormat format = new DecimalFormat("#.#####", symbols);
value = format.parse(format.format(41251.50000000012343));
6 голосов
/ 22 апреля 2010

Тот факт, что ваша строка форматирования использует . в качестве десятичного разделителя, а исключение жалуется на ,, указывает на проблему локали; то есть DecimalFormat использует другой Locale для форматирования числа, отличного от Double.valueOf.

Как правило, вы должны создать NumberFormat на основе определенной локали.

Locale myLocale = ...;
NumberFormat f = NumberFormat.getInstance(myLocale);

Из JavaDocs DecimalFormat :

Чтобы получить NumberFormat для конкретной локали, включая локаль по умолчанию, вызовите один из заводских методов NumberFormat, например, getInstance (). В общем случае не вызывайте конструкторы DecimalFormat напрямую, поскольку фабричные методы NumberFormat могут возвращать подклассы, отличные от DecimalFormat.

Однако , как BalusC указывает на , попытка отформатировать двойной тип как String, а затем проанализировать String обратно в двойной тип - довольно неприятный запах кода. Я подозреваю, что вы имеете дело с проблемами, когда вы ожидаете десятичное число с фиксированной точностью (например, денежная сумма), но сталкиваетесь с проблемами, потому что double - это число с плавающей запятой, что означает, что много значений (например, 0.1) не может быть выражено в точности как double / float. В этом случае правильный способ обработки десятичного числа с фиксированной точностью - использовать BigDecimal.

5 голосов
/ 22 апреля 2010

Используйте Locale.getDefault(), чтобы получить десятичный разделитель вашей системы, который вы также можете установить. Вы не можете использовать разные разделители одновременно, так как другой обычно используется в качестве разделителя для тысяч: 2.001.000,23 <=> 2,001,000.23

3 голосов
/ 09 сентября 2015

похоже, что вы используете в качестве десятичного разделителя запятую ",". Чтобы получить "." в качестве десятичного разделителя вы должны будете объявить:

DecimalFormat dFormat =new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.ENGLISH));
3 голосов
/ 22 апреля 2010

Для ',' вместо '.' вам придется изменить локаль.

Для количества десятичных знаков используйте setMaximumFractionDigits(int newValue).

В остальном см. Javadoc .

2 голосов
/ 30 мая 2016

Реальное решение таково: не используйте числа с плавающей запятой для всего, что необходимо посчитать с точностью:

  • Если вы имеете дело с валютой, не используйте двойное числодолларов, используйте целое число центов.
  • Если вы имеете дело с часами времени и вам необходимо сосчитать четверть часа и 10-минутные интервалы, используйте целое число минут.

Число с плавающей запятой почти всегдаприближение некоторой реальной стоимости.Они подходят для измерений и расчета физических величин (с максимальной степенью точности) и для статистических артефактов.

Дурачиться с округлением числа с плавающей запятой до нескольких цифр - это запах кода: это расточительно, и вы никогдадействительно убедитесь, что ваш код будет работать правильно во всех случаях.

2 голосов
/ 23 апреля 2010

С чем-то связано, но не с ответом на вопрос: попробуйте переключиться на BigDecimal вместо double и float. У меня было много проблем со сравнениями по этим типам, и теперь я могу использовать BigDecimal.

2 голосов
/ 22 апреля 2010

Вы не можете изменить внутреннее представление double / Double таким образом.

Если вы хотите изменить (человеческое) представление, просто оставьте его String.Таким образом, оставьте это Double#valueOf() и используйте String результат DecimalFormat#format() в своей презентации.Если вы когда-нибудь захотите провести с ним вычисления, вы всегда можете преобразовать обратно в реальное Double, используя DecimalFormat и Double#valueOf().

Кстати, согласно вашей жалобе Япытаясь избавиться от ненужных символов после десятичного разделителя моего двойного значения , знаете ли вы о внутренностях чисел с плавающей запятой ?Пахнет немного так, как будто вы используете неформатированные двойные числа в уровне представления, и вы не понимаете, что при использовании среднего пользовательского интерфейса вы можете просто представить их, используя DecimalFormat без необходимости конвертировать обратно в Double.

0 голосов
/ 07 апреля 2017

Мой код функции:

 private static double arrondi(double number){
         DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
         symbols.setDecimalSeparator('.');
         DecimalFormat format = new DecimalFormat("#.#####", symbols);
         return Double.valueOf(format.format(number));
     }
...