Представление денежных ценностей в Java

Я понимаю, что BigDecimal рекомендуется для представления денежных значений в Java. Что ты используешь? Есть ли лучшая библиотека, которую вы предпочитаете использовать вместо этого?

14 ответов

Решение

BigDecimal весь путь. Я слышал о некоторых людях, создающих свои собственные Cash или же Money классы, которые инкапсулируют денежную стоимость с валютой, но под кожей это все еще BigDecimalвероятно с BigDecimal.ROUND_HALF_EVENокругления.

Редактировать: как Дон упоминает в своем ответе, есть проекты с открытым исходным кодом, такие как timeandmoney, и хотя я приветствую их за попытку не дать разработчикам изобретать велосипед, у меня просто нет достаточной уверенности в использовании библиотеки pre-alpha для использования это в производственной среде. Кроме того, если вы покопаетесь под капотом, вы увидите, что они используютBigDecimal тоже.

Людям, прибывающим сюда поисковыми системами, может быть полезно узнать о JodaMoney: http://www.joda.org/joda-money/.

Я не выражаю свое мнение здесь, но есть довольно хорошие аргументы против BigDecimal, которые кто-то, вероятно, должен выкинуть:

http://lemnik.wordpress.com/2011/03/25/bigdecimal-and-your-money/

Удобная библиотека, с которой я столкнулся ранее, это библиотека Joda-Money. Одна из его реализаций действительно основана на BigDecimal. Он основан на спецификации ISO-4217 для валют и может поддерживать настраиваемый список валют (загружается через CVS).

Эта библиотека имеет небольшое количество файлов, которые можно быстро просмотреть, если понадобятся изменения. Joda-Money выпускается под лицензией Apache 2.0.

Если вы просто используете доллары и центы, я бы использовал long (смещение на 2 знака после запятой). Если вам нужно больше деталей, большой десятичный может быть путь.

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

Также, если вы используете определение своего собственного класса и интерфейса, вы можете заменить реализацию по своему желанию.

BigDecimal или другое представление с фиксированной запятой - это то, что обычно нужно для денег.

Плавающая запятая (Double, Float) представления и вычисления неточны, что приводит к ошибочным результатам.

Вы должны быть очень осторожны, имея дело со временем и деньгами.

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

Но я не уверен насчет BigDecimal.

В большинстве случаев вам будет хорошо, если вы просто будете отслеживать центы в int или long. Таким образом, вы никогда не имеете дело с десятичным знаком.

Вы показываете только доллары, когда вы печатаете его. Всегда работайте с внутренними центами, используя целые числа. Это может быть сложно, если нужно разделить или нужно использовать Math.abs().

Тем не менее, вы можете заботиться о состоянии полцента или даже одной сотой процента. Я не знаю, что хороший способ сделать это. Возможно, вам просто нужно иметь дело с тысячными центами и использовать длинные. Или, может быть, вы будете вынуждены использовать BigDecimal

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

Я чувствую, что мой совет не является полным, поэтому, пожалуйста, вложите в него больше. Вы имеете дело с опасными типами!

Создание класса Money - это путь. Используя BigDecimal(или даже int) внизу. Затем используя класс Currency для определения соглашения о округлении.

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

Есть лучшая библиотека, время и деньги. ИМО, он намного превосходит библиотеки, предоставляемые JDK для представления этих двух концепций.

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

Определенно не BigDecimal. Существует так много специальных правил для округления и представления, о которых вам нужно беспокоиться.

Мартин Фаулер рекомендует использовать специальный класс Money для представления сумм в валюте, а также реализует правила конвертации валют.

Я бы инкапсулировал BigDecimal в классе Money, который также имеет валюту, как кто-то упоминал выше. Важно то, что вы проводите огромное количество юнит-тестов, особенно если работаете с разными валютами. Также будет хорошей идеей, если вы добавите удобный конструктор, который принимает строку или метод фабрики, который делает то же самое, чтобы вы могли написать свои тесты примерно так:

   assertEquals(Money.create("100.0 USD").add("10 GBP"),Money.create("116 USD"));

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

http://lemnik.wordpress.com/2011/03/25/bigdecimal-and-your-money

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

Вы можете использовать класс DecimalFormat при окончательном отображении значения валюты. Он обеспечивает поддержку локализации и довольно расширяем.

Другие вопросы по тегам