Как сделать конвертер валют в java

Добавил пользователь Евгений Кузнецов
Обновлено: 04.10.2024

Большая часть корпоративных приложений оперирует денежными суммами. Деньги обычно представлены двумя частями: числовым значением и валютой. Мы имеем дело с деньгами в наших программах каждый день, но JDK, к сожалению, не содержит стандартных типов предназначенных для работы с ними. Нам разработчикам необходимо знать, какой тип данных подходит для представления денежных величин. Попробуем с этим разобраться.

1. float и double

Первое что приходит на ум – использовать типы с плавающей точкой (float и double). Однако, Джошуа Блох, автор Effective Java, не рекомендует использовать эти типы данных, если требуются точные значения.

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

Вместо float и double Джошуа рекомендует использовать BigDecimal, а также целочисленные типы int и long. Рассмотрим оба эти варианта.

2. int и long

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

  • Хорошая производительность при выполнении арифметических операций.
  • Нужно отслеживать положение десятичной точки;
  • Обрабатываемые значения не должны быть слишком большими (учитываем максимально возможные значения для типов int и long).

3. BigDecimal

Самый простой вариант – использовать BigDecimal вместо double:

  • Полный контроль над округлением. Можно выбрать один из восьми режимов округления. Это может пригодиться при выполнении финансовых вычислений с жестко заданным алгоритмом округления;
  • Не нужно отслеживать положение десятичной точки.
  • Менее удобен в использовании, чем примитивные типы;
  • Существенно медленнее в арифметических операциях.

Хотя если не предполагается массовых расчетов, то последний недостаток не так важен.

Добавляем валюту

Самое простое, что мы можем сделать – добавить поле типа String для хранения значения валюты:

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

Давайте сделаем его типобезопасным, введя перечисление валют (enum). При этом мы должны не забывать про различные аспекты интернационализации, например, такие как ISO-4217.

Кстати, в JDK есть класс java.util.Currency, который работает с ISO-4217. Валюты в нём идентифицируются по их кодам. Они могут быть представлены в коде двумя способами: трехбуквенным кодом и/или трехзначным цифровым кодом. Используя java.util.Currency мы можем получить следующую информацию:

  • Код валюты
  • Символ валюты или её краткое наименование
  • Наименование валюты
  • Количество цифр после запятой

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

В этом случае мы могли бы ввести служебный класс, который отвечает за такие проверки:

Но при этом необходимо учесть следующие моменты:

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

Добавление абстракции для представления денег становится всё более и более очевидным решением. Мартин Фаулер написал статью, описывающую абстракцию, которая представляет деньги и решает следующие проблемы:

  • Класс Money является единственным типом, который отвечает за работу с деньгами (принцип единственной ответственности).
  • Нет необходимости в служебных классах, потому что класс Money будет единственным классом ответственным за этот вид проверки.

JSR-354 (Money and Currency API)

Отсутствие единого подхода при работе с денежными величинами и валютами в итоге привело к созданию спецификации стандартного Money and Currency API (JSR-354). Реализация спецификации должна предусматривать следующее:

  • Предоставление API для обработки и расчета денежных величин;
  • Определение классов представляющих валюты и денежные величины;
  • Округление и форматирование денежных величин;
  • Конвертация валют;

На сегодняшний день уже есть готовые реализации Money and Currency API по спецификации JSR-354. Информацию о готовых решениях можно найти, например, на javamoney.github.io

Давайте рассмотрим одну из реализаций java-money – библиотеку Moneta.

4. Moneta

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

Основные классы в Moneta: Monetary, Money, FastMoney, а также интерфейсы CurrencyUnit и MonetaryAmount.

CurrencyUnit

CurrencyUnit моделирует свойства валюты. Его экземпляр можно получить через вызов фабричного метода Monetary.getCurrency().

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

currencyCode: RUB
numericCode: 643
defaultFractionDigits: 2

Если мы попытаемся передать в метод getCurrency() несуществующий трехбуквенный код валюты, то получим исключение UnknownCurrencyException:

Exception in thread "main" UnknownCurrencyException [currencyCode=ZZZ]

Такие ситуации, конечно же, нужно обрабатывать.

MonetaryAmount

MonetaryAmount – это числовое представление денежной величины. Он всегда связан с CurrencyUnit и определяет денежное представление валюты.

Классы Money и FastMoney реализуют интерфейс MonetaryAmount. Разница между ними в том, что они используют разные типы данных для числового представления денежных величин. FastMoney использует long, а Money – BigDecimal.Если нам важна производительность, то лучше воспользоваться классом FastMoney.

ruble: RUB
monetaryAmount: RUB 100.000000000000000000000000000000000000000000000000000000000000000
money: RUB 50
fastMoney: RUB 50.00000

Денежная арифметика

Мы можем выполнять сложение, вычитание, умножение, деление и другие денежные арифметические операции используя методы предоставляемые классом MonetaryAmount. Нужно учесть, что арифметические операции в некоторых ситуациях могут вызывать исключение ArithmeticException. Очевидно, что это может произойти, например, при попытке деления денежной величины на ноль:

Exception in thread "main" java.lang.ArithmeticException: BigInteger divide by zero

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

Расчет сумм

Общая сумма может быть рассчитана несколькими способами, один из которых – цепочки вызовов методов сложения:

Общая сумма: RUB 35.9

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

Округление денежных сумм

Для округления денежных сумм воспользуемся методом getDefaultRounding класса Monetary:

Начальная сумма: RUB 7.6886332
Округленная сумма: RUB 7.69

Конвертация валют

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

USD: 1
RUB: 65.203045

Верно. Полученный результат полностью совпадает с данными курса валют, представленного на сайте Центрального банка РФ на 07.08.2019 г.

Форматирование денежных сумм

Форматирование позволяет получить доступ к форматам денежных единиц на основе региональных представлений с помощью java.util.Locale:

Начальное значение: RUB 35.5
Отформатированное значение: RUB 35,50

Более того, мы можем создавать свои собственные форматы для отображения денежных величин наших валют. Для этого воспользуемся методом format класса MonetaryFormats. Ниже в примере мы определили наш собственный формат, задавая свойство pattern построителя форматов AmountFormatQueryBuilder:

RUB 1
00001,00 Р

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

Заключение

В этой статье мы рассмотрели типы данных пригодные для оперирования денежными величинами, начиная с примитивных типов с плавающей точкой до полноценной реализации спецификации JSR-354 (Money and Currency API). Какой из них использовать – зависит от проекта. Если в приложении предусмотрена мультивалютность, то стоит присмотреться к реализациям JSR-354. Если в приложении все операции осуществляются только с одной валютой, то использование BigDecimal или long может оказаться вполне удовлетворительным решением.

Альта – Системс

Разработка и внедрение информационных систем, web-приложений, автоматизация бизнес - процессов, создание и обслуживание сайтов, проектирование и монтаж локальных вычислительных сетей

Конвертер валют на JavaScript. Видео урок

JavaScript

Урок по написанию конвертера валют на JavaScript. Получаем актуальные данные курса рубля ко всем валютам. Выводим их на страницу и после на основании введенной суммы высчитываем сумму. Переводим рубли в доллары, евро и британские фунты.

Видео урок

JSR 354 определяет новый Java API для работы с деньгами и валютами, который планируется включить в Java 9. В этом посте мы рассмотрим текущее состояние эталонной реализации:
JavaMoney .

Как и мой пост об API даты / времени Java 8, этот пост будет в основном основан на коде, который показывает новый API.

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

Денежные значения являются ключевой особенностью многих приложений, однако JDK практически не поддерживает их. Существующий класс java.util.Currency является строго структурой, используемой для представления текущих валют ISO 4217, но не связанных значений или пользовательских валют. JDK также не поддерживает денежную арифметику или конвертацию валюты, а также стандартный тип значения для представления денежной суммы.

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

Все спецификации классов и интерфейсов находятся в пакете javax.money. *.

Мы начнем с двух основных интерфейсов CurrencyUnit и MonetaryAmount. После этого мы рассмотрим обменные курсы, конвертацию и форматирование валют.

CurrencyUnit и MonetaryAmount

CurrencyUnit моделирует валюту. CurrencyUnit очень похож на существующий класс java.util.Currency, за исключением того, что он допускает пользовательские реализации. Согласно спецификации должно быть возможно, что java.util.Currency реализует CurrencyUnit. Экземпляры CurrencyUnit можно получить с помощью фабрики MonetaryCurrencies:

MontetaryAmount представляет собой конкретное числовое представление денежной суммы. MonetaryAmount всегда привязан к CurrencyUnit. Как и CurrencyUnit, MonetaryAmount — это интерфейс, который поддерживает различные реализации. Реализации CurrencyUnit и MonetaryAmount должны быть неизменяемыми, поточно-ориентированными, сериализуемыми и сопоставимыми.

Web /> HTML CSS JS IT

Web /> HTML CSS JS IT

Web /> HTML CSS JS IT запись закреплена

Урок по написанию конвертера валют на JavaScript

— Получаем актуальные данные курса рубля ко всем валютам.
— Выводим их на страницу в информер.
— На основании введенной суммы высчитываем сумму.
— Переводим рубли в доллары, евро и британские фунты.

🔽

Ссылки на стартовый проект и сервис с актуальными курсами в описании под видео.

Читайте также: