DecimalFormat и Double.valueOf()

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

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? Любые другие мысли?

Ответ 1

Через

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

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

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

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

Ответ 2

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

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

DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
symbols.setDecimalSeparator('.');
DecimalFormat format = new DecimalFormat("#.#####", symbols);
value = format.parse(format.format(41251.50000000012343));

Ответ 3

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

В общем, вы должны построить NumberFormat на основе определенной локали.

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

Из JavaDocs DecimalFormat:

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

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

Ответ 4

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

Ответ 5

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

DecimalFormat dFormat =new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.ENGLISH));

Ответ 6

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

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

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

Ответ 7

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

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

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

Ответ 8

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

Ответ 9

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

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

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

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

Ответ 10

Моя кодовая функция:

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