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

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

взгляните на JSR 354

yegor256 08.02.2013 15:16

Вот один класс валюты, который вы можете скопировать и расширить: java-articles.info/articles/?p=254

Gilbert Le Blanc 23.07.2013 21:24

Также см. Эталонную реализацию JSR-354 github.com/JavaMoney/jsr354-ri

beat 12.12.2016 16:38
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
94
3
43 340
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

Ответ принят как подходящий

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

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

+1. Мы решили добавить класс контейнера, который также потребляет валюту. Это удобно при отображении денежных значений в таблицах.

Daniel Hiller 13.11.2008 09:01

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

ninesided 13.11.2008 13:34

@ninesided дает отличный пример того, почему прокатить собственный - плохой ответ. «Да, кстати, это не работает для $ CURRENCY_X». Это хороший знак, что он также не работает для многих других валют.

James Moore 01.11.2011 18:05

@JamesMoore Я не согласен с тем, что «использовать свой собственный» - плохой подход, вам просто нужно знать о возможных ограничениях выбранного вами подхода, поэтому я упомянул об этом. Реализовать разные правила округления для каждой валюты тривиально, но если ваша система должна работать только в долларах США или евро, вам не нужно слишком много разрабатывать.

ninesided 01.11.2011 18:14

Взгляните на stackoverflow.com/questions/5134237/… только по одной причине, по которой BigDecimal является проблемой. Бухгалтерский учет на всей планете - это просто болото особых случаев, и попытка замазать их все под ковриком BigDecimal просто не работает.

James Moore 01.11.2011 18:15

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

ninesided 01.11.2011 18:31

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

vach 23.01.2015 17:06

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

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

Строго говоря, BigDecimal также неточен; он просто лучше соответствует десятичному округлению, к которому мы привыкли в повседневной жизни, и позволяет указывать режимы округления.

Michael Borgwardt 16.07.2009 17:17

@Michael Borgwardt BigDecimal отличается от IEEE FP тем, что указан явный масштаб. Хотя не все операции точны, это гарантирует, что набор операций и поведения будет точным всегда и масштабом будет постоянный, тогда как масштаб для IEEE FP уменьшается со значением.

user166390 13.03.2011 00:34

При чем здесь деньги? Бухгалтерские организации по всему миру обычно предъявляют особые требования к расчетам в их валюте. Точно ли BigDecimal соответствует каждому из этих стандартов? Произойдет ли это в следующем году, когда эти стандарты изменятся? А BigDecimal даже близко не подходит к указанию полезных правил округления для валют.

James Moore 01.11.2011 18:00

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

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

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

Осторожно, даже длинный срок может оказаться слишком коротким, чтобы удерживать федеральный долг США в центах ... если не сейчас, то через несколько лет.

Ingo 23.07.2013 22:56

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

Bill K 24.07.2013 00:01

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

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

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

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

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

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

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

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

Зачем вас «заставляют» использовать BigDecimal? В чем вы не уверены? Он явно превосходит работу с центами, поскольку позволяет явно указывать режимы округления.

Michael Borgwardt 16.07.2009 17:20

@MichaelBorgwardt: да, он позволяет вам указать крошечное подмножество режимов округления, которые вам нужны для валют. Так? (Подсказка: решение об округлении валют, как правило, принимают национальные бухгалтерские организации. Они с радостью подбрасывают странные особые случаи. См. stackoverflow.com/questions/5134237/… только для одной из многих забавных причин, по которым округление BigDecimal здесь совершенно бесполезно.)

James Moore 01.11.2011 18:12

@ Джеймс: Как именно это «бесполезно»? Насколько сложнее реализовать эти особые случаи с BigDecimal, чем с чем-то еще?

Michael Borgwardt 01.11.2011 20:56

Хорошо, совершенно бесполезно - это слишком сильно. В сложном классе, который абстрагирует валюту, правила округления BigDecimal, вероятно, будут полезны в некоторых конкретных случаях для создания подмножества способов округления валюты. Но в общем случае правила округления для валют требуют механизмов, которые могут меняться с течением времени (поскольку бухгалтерские агентства составляют правила и могут их изменять). Речь идет не о евро (или о том, что заменит евро в следующем месяце ...) или о долларах в 2011 году, а о валюте, поэтому вам придется иметь дело с множеством неприятных сложностей.

James Moore 01.11.2011 22:10

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

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

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

Этот ответ был опубликован три года назад. Сегодня, судя по этой ссылке, проект timeandmoney все еще находится в стадии предварительной альфа-версии.

James Moore 01.11.2011 18:02

@JamesMoore Хороший звонок. Ответу сейчас 7 лет, а проект все еще нестабилен.

Navin 07.09.2015 17:26

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

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

и базовый тип данных его класса Money? BigDecimal.

ninesided 13.11.2008 23:42

Это не правда. Вы можете использовать Integer в классе денег, что и делает Мартин. Я делал это много раз.

egervari 24.04.2011 08:50

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

James Moore 01.11.2011 18:08

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

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

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

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

Спасибо. Я хотел добавить дополнительную заметку о Joda Money. Вы им пользовались?

dshaw 27.01.2010 17:37

+1 выглядит интересно, рад видеть, что под капотом BigDecimal!

ninesided 01.11.2011 18:22

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

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

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

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

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

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

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

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

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

Slater Victoroff 23.07.2013 21:29

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