Я понимаю, что BigDecimal является наилучшей практикой для представления денежных величин в Java. Что ты используешь? Есть ли лучшая библиотека, которую вы бы предпочли использовать?
Вот один класс валюты, который вы можете скопировать и расширить: java-articles.info/articles/?p=254
Также см. Эталонную реализацию JSR-354 github.com/JavaMoney/jsr354-ri




BigDecimal полностью. Я слышал, что некоторые люди создают свои собственные классы Cash или Money, которые инкапсулируют денежную стоимость с валютой, но под кожей это все еще BigDecimal, вероятно, с округлением BigDecimal.ROUND_HALF_EVEN.
Редактировать: Как упоминает Дон в его ответ, существуют проекты с открытым исходным кодом, такие как время и деньги, и хотя я аплодирую им за попытки помешать разработчикам изобретать велосипед, я просто не уверен в пре-альфа-библиотеке, чтобы использовать ее в производственная среда. К тому же, если копнуть под капотом, то увидишь они тоже используют BigDecimal.
+1. Мы решили добавить класс контейнера, который также потребляет валюту. Это удобно при отображении денежных значений в таблицах.
да, это довольно распространенный подход, и он имеет большой смысл. Одно предостережение - когда вам приходится иметь дело с японской йеной, поскольку у них нет незначительного номинала валюты, такого как центы, поэтому для этого нужны собственные правила округления.
@ninesided дает отличный пример того, почему прокатить собственный - плохой ответ. «Да, кстати, это не работает для $ CURRENCY_X». Это хороший знак, что он также не работает для многих других валют.
@JamesMoore Я не согласен с тем, что «использовать свой собственный» - плохой подход, вам просто нужно знать о возможных ограничениях выбранного вами подхода, поэтому я упомянул об этом. Реализовать разные правила округления для каждой валюты тривиально, но если ваша система должна работать только в долларах США или евро, вам не нужно слишком много разрабатывать.
Взгляните на stackoverflow.com/questions/5134237/… только по одной причине, по которой BigDecimal является проблемой. Бухгалтерский учет на всей планете - это просто болото особых случаев, и попытка замазать их все под ковриком BigDecimal просто не работает.
Я не понимаю, как это связано с использованием BigDecimal и «прокруткой собственного», наверняка вы столкнетесь с теми же проблемами, если будете использовать «готовое» решение, тем более что подавляющее большинство сторонних библиотек используют BigDecimal. все равно под капотом?
BigDecimal медленный и использует больше памяти, поэтому больше GC, следовательно, еще медленнее, если вы заботитесь о скорости и у вас много денежных операций, вы должны использовать long с точной реализацией ...
BigDecimal или другое представление с фиксированной точкой - это то, что обычно нужно для денег.
Представления и вычисления с плавающей запятой (Double, Float) неточны, что приводит к ошибочным результатам.
Строго говоря, BigDecimal также неточен; он просто лучше соответствует десятичному округлению, к которому мы привыкли в повседневной жизни, и позволяет указывать режимы округления.
@Michael Borgwardt BigDecimal отличается от IEEE FP тем, что указан явный масштаб. Хотя не все операции точны, это гарантирует, что набор операций и поведения будет точным всегда и масштабом будет постоянный, тогда как масштаб для IEEE FP уменьшается со значением.
При чем здесь деньги? Бухгалтерские организации по всему миру обычно предъявляют особые требования к расчетам в их валюте. Точно ли BigDecimal соответствует каждому из этих стандартов? Произойдет ли это в следующем году, когда эти стандарты изменятся? А BigDecimal даже близко не подходит к указанию полезных правил округления для валют.
Если вы просто используете доллары и центы, я бы использовал длинное (смещение на 2 десятичных знака). Если вам нужна более подробная информация, возможно, вам подойдут большие десятичные дроби.
В любом случае, я бы, вероятно, расширил класс, чтобы иметь .toString (), который использует правильный формат, и в качестве места для размещения других методов, которые могут появиться (долгое время умножение и деление пойдет наперекосяк, если десятичное число isn не отрегулировано)
Кроме того, если вы используете свой собственный класс и интерфейс, вы можете заменить реализацию по своему желанию.
Осторожно, даже длинный срок может оказаться слишком коротким, чтобы удерживать федеральный долг США в центах ... если не сейчас, то через несколько лет.
Я согласен - любые огромные суммы долларов (или, может быть, если вы отслеживаете деньги в иенах), вам следует использовать BigDecimal, но даже в этом случае я бы серьезно подумал об использовании для этого класса контейнера. Я думаю, что большая часть сложности программирования возникает из-за того, что люди не определяют небольшие простые классы вокруг коллекций и внутренних типов.
Вы должны быть очень осторожны, имея дело со временем и деньгами.
Я надеюсь, что когда вы работаете с деньгами, каждый должен знать, что нельзя использовать поплавок или дубль.
Но насчет BigDecimal я не уверен.
В большинстве случаев все будет в порядке, если вы просто будете отслеживать центы в int или long. Таким образом, вы никогда не будете иметь дело с десятичным знаком.
Вы показываете только доллары, когда распечатываете их. Всегда работайте с внутренними центами, используя целые числа. Это может быть сложно, если нужно разделить или использовать Math.abs ().
Тем не менее, вы можете рассчитывать на полцента или даже сотую долю цента. Я не знаю, как это сделать. Возможно, вам просто придется иметь дело с тысячными центами и использовать длинную. Или, может быть, вам придется использовать BigDecimal
Я бы прочитал об этом гораздо больше, но игнорирую всех, кто начинает говорить об использовании числа с плавающей запятой или удвоения для представления денег. Они просто напрашиваются на неприятности.
Я считаю, что мой совет неполный, поэтому, пожалуйста, вдавите в него больше. Вы имеете дело с опасными типами!
Зачем вас «заставляют» использовать BigDecimal? В чем вы не уверены? Он явно превосходит работу с центами, поскольку позволяет явно указывать режимы округления.
@MichaelBorgwardt: да, он позволяет вам указать крошечное подмножество режимов округления, которые вам нужны для валют. Так? (Подсказка: решение об округлении валют, как правило, принимают национальные бухгалтерские организации. Они с радостью подбрасывают странные особые случаи. См. stackoverflow.com/questions/5134237/… только для одной из многих забавных причин, по которым округление BigDecimal здесь совершенно бесполезно.)
@ Джеймс: Как именно это «бесполезно»? Насколько сложнее реализовать эти особые случаи с BigDecimal, чем с чем-то еще?
Хорошо, совершенно бесполезно - это слишком сильно. В сложном классе, который абстрагирует валюту, правила округления BigDecimal, вероятно, будут полезны в некоторых конкретных случаях для создания подмножества способов округления валюты. Но в общем случае правила округления для валют требуют механизмов, которые могут меняться с течением времени (поскольку бухгалтерские агентства составляют правила и могут их изменять). Речь идет не о евро (или о том, что заменит евро в следующем месяце ...) или о долларах в 2011 году, а о валюте, поэтому вам придется иметь дело с множеством неприятных сложностей.
Создание класса Money - это лучший способ. Используя BigDecimal (или даже int) внизу. Затем с помощью класса Currency для определения соглашения об округлении.
К сожалению, без перегрузки операторов Java делает довольно неприятным создание таких базовых типов.
Есть лучшая библиотека, время и деньги. IMO, он намного превосходит библиотеки, предоставляемые JDK для представления этих двух концепций.
Этот ответ был опубликован три года назад. Сегодня, судя по этой ссылке, проект timeandmoney все еще находится в стадии предварительной альфа-версии.
@JamesMoore Хороший звонок. Ответу сейчас 7 лет, а проект все еще нестабилен.
Определенно не BigDecimal. Существует так много специальных правил округления и представления, о которых вам нужно беспокоиться.
Мартин Фаулер рекомендует реализовать специальный класс Деньги для представления сумм в валюте, а также реализует правила конвертации валюты.
и базовый тип данных его класса Money? BigDecimal.
Это не правда. Вы можете использовать Integer в классе денег, что и делает Мартин. Я делал это много раз.
Однако рекомендация верна; денежные расчеты - это огромное количество особых случаев, которые со временем меняются. BigDecimal может быть полезен как крошечная часть решения, но, конечно, не в общем.
Вы можете использовать класс 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. Вы им пользовались?
+1 выглядит интересно, рад видеть, что под капотом BigDecimal!
Эй, вот очень интересная статья о 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. Да, это подразумевает использование долларов в качестве валюты и ограничивает суммы, но такие ограничения вполне приемлемы для многих случаев использования, и все валюты в любом случае имеют особые случаи для округления и субденоминации, поэтому «универсального» решения не существует.
Похоже, это комментарий к другому сообщению, а не фактический ответ. К тому же он излишне едкий. Пожалуйста, постарайтесь быть более вежливым в будущем.
взгляните на JSR 354