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));
}