DecimalFormat и двойной.метод 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 класса? Есть другие мысли?

10 ответов


By

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

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

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

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


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

в основном то, что вам нужно сделать, это создать отформатированные даты с '.'separator so Double.valueOf может это прочитать. Как указано в комментариях, вы можете использовать тот же формат для анализа значения, а не использовать Double.valueOf.

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

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

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

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

из JavaDocs DecimalFormat:

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

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

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


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

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

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

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

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


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


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

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

до конца, см. javadoc.


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

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

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

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


моя функция код :

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