java人民币换欧元_关于java:用于存储货币汇率的设计
我已经开始了一个信贷管理的新项目,现在我不得不处理货币兑换。 (例如,欧元->美元)因此,我做了一些头脑风暴,并得到了以下信息:
货币是抽象的,每种新货币都是接口的实现
建立了一个汇率类别,该汇率类别存储对(pair,pair,double)的数组列表(我想到的是欧元,美元,1.14->欧元对美元的汇率是1.14)并具有以下功能:货币汇率存储,一个用于正确汇率的查找器(该函数将当前货币和新货币作为参数,并在列表中进行搜索,然后返回适当的货币)和一个实用函数,该函数确定货币对的索引。
现在,我正在考虑性能。我相信我的设计包含一些冗余:如果我有欧元兑美元,我就必须有美元兑欧元。此外,对于大量条目(假设100k),我的存储(pair 的数组列表)的效率如何?我有什么选择?
我知道有很多数据结构,我真的不知道该选什么。
现在,对于代码:
转化率等级:
package currency;
import javafx.util.Pair;
import loggers.ILogger;
import java.util.ArrayList;
public class ConversionRates implements IConversionRate {
private ArrayList, Double>> conversionRates;
private ILogger log;
public ConversionRates(ArrayList, Double>> conversionRates, ILogger log) {
this.conversionRates = conversionRates;
this.log = log;
}
@Override
public double find(ICurrency firstCurrency, ICurrency secondCurrency) {
log.add("Performing rate identification");
String first = firstCurrency.getId();
String second = secondCurrency.getId();
int index = searchPairs(first, second);
Pair, Double> selectedPair = conversionRates.get(index);
double rate = selectedPair.getValue();
return rate;
}
private int searchPairs(String first, String second) {
Pair pairContainingRate = new Pair<>(first, second);
for (int index = 0; index < conversionRates.size(); index++) {
if (conversionRates.get(index).getKey().equals(pairContainingRate)) {
log.add("Successfully found target" + first +"/" + second);
return index;
}
}
log.add("Failed to find target" + first +"/" + second);
return -1;
}
@Override
public void add(Pair, Double> newRate) {
log.add("Added new rate" + newRate);
conversionRates.add(newRate);
}
@Override
public void update(ArrayList, Double>> newRates) {
log.add("Updated rates");
conversionRates.clear();
conversionRates.addAll(newRates);
}
@Override
public void remove(Pair, Double> redundantRate) {
log.add("Removed rate" + redundantRate);
conversionRates.remove(redundantRate);
}
}
ConversionRates接口:
package currency;
import javafx.util.Pair;
import java.util.ArrayList;
public interface IConversionRate {
double find(ICurrency euro, ICurrency newCurrency);
void add(Pair,Double> newRate);
void update(ArrayList< Pair,Double> > newRates);
void remove(Pair,Double> redundantRate);
}
货币界面:
package currency;
public interface ICurrency {
double convertTo(double amount, ICurrency newCurrency);
double convert(double oldCurrencyAmount, double conversionRateToNewCurrency);
String getId();
}
货币实现(由于欧元完全相同,因此我仅列出欧元):
package currency;
public class Euro implements ICurrency {
private String id;
private IConversionRate conversionRateFinder;
public Euro(String id, IConversionRate conversionRateBuilder) {
this.id = id;
this.conversionRateFinder = conversionRateBuilder;
}
@Override
public double convertTo(double amount, ICurrency newCurrency) {
double currentConversionRate = conversionRateFinder.find(this, newCurrency);
double newAmount = newCurrency.convert(amount,currentConversionRate);
return newAmount;
}
@Override
public double convert(double oldCurrencyAmount, double currentConversionRate) {
return oldCurrencyAmount*currentConversionRate;
}
public String getId() {
return id;
}
}
我也想听听您的一般设计。
在关心性能之前,您应该关心可读性。我不知道ArrayList ,Double >>可能包含什么。定义类,枚举,它们的名称应清楚地表明它们所代表的含义。请注意,Java和Guava均不包含Pair类,这恰恰是因为它鼓励开发人员编写不可读的代码,例如您所拥有的代码。
第一对代表货币,双倍代表从第一对第二货币的实际汇率。
然后,定义并使用具有三个字段的CurrencyConversion类:Currency sourceCurrency,Currency targetCurrency,double conversionRate。其方式更具可读性。它可以包含实际计算转化的方法。它可以包含简单地通过交换两种货币并反转汇率来创建反向CurrencyConversion的方法。它可以在施工时验证费率的有效性。它可以具有toString()方法,该方法返回对象的可读描述等。
听起来不错。因此,我应该创建该类并将其注入每个货币对象并执行转换。但是,我应该如何处理汇率的存储,或者应该如何正确执行汇率汇率的检测?提前坦克,我为这些错误表示歉意,我仍然是菜鸟。
这取决于。这是一个真正的应用程序,存储实际上意味着持久存储吗?如果是这样,请使用数据库。如果它是一个玩具项目,其中的所有内容都在内存中,则您可能应该使用Map (其中CurrencyPair包含源货币和目标货币)是不可变的,并定义适当的equals()和hashCode()方法。这将允许O(1)查找。
这不是一个真正的应用程序,但我要考虑到这一点。我将使用序列化。
也许Joda-Money项目可能会有所帮助?
我认为您应该更简单一些。我看不到使用货币接口的原因,特别是在这种情况下,因为我看不到您的实现将如何需要不同的提供程序。每个Currency用一个符号和该货币的一组汇率表示。
public class Currency {
private final String symbol;
private final Set rates = new HashSet<>();
public Currency(String symbol) {
this.symbol = symbol;
}
public BigDecimal convert(Currency currency, BigDecimal amount) {
return findExchangeRate(currency).getRate().multiply(amount).setScale(2, RoundingMode.HALF_DOWN);
}
public String getSymbol() {
return symbol;
}
public ExchangeRate findExchangeRate(Currency currency) {
for(ExchangeRate rate: rates) {
if ( rate.getCurrency().equals(currency)) {
return rate;
}
}
throw new IllegalArgumentException("Currency not found:" + currency);
}
public void setExchangeRate(ExchangeRate rate) {
if ( rates.contains(rate) ) rates.remove(rate);
rates.add(rate);
}
public boolean removeExchangeRate(ExchangeRate rate) {
return rates.remove(rate);
}
ExchangeRate是所交换货币的汇率,因此您无需每次都重复该货币的1.0。不要忘了@Override hashCode和equals,这样Set逻辑将正常工作。
public class ExchangeRate {
private final Currency currency;
private final BigDecimal rate;
public ExchangeRate(Currency currency, BigDecimal rate) {
this.currency = currency;
this.rate = rate;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((currency == null) ? 0 : currency.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ExchangeRate other = (ExchangeRate) obj;
if (currency == null) {
if (other.currency != null)
return false;
} else if (!currency.equals(other.currency))
return false;
return true;
}
使用它非常简单。
Currency usd = new Currency("USD");
Currency eur = new Currency("EUR");
usd.setExchangeRate(new ExchangeRate(eur, new BigDecimal("0.87540")));
eur.setExchangeRate(new ExchangeRate(usd, new BigDecimal("1.14233")));
BigDecimal myMoney = new BigDecimal("1000.00");
myMoney = usd.convert(eur, myMoney);
System.out.println("My Euros:" + myMoney);
myMoney = eur.convert(usd, myMoney);
System.out.println("My Dollars:" + myMoney);
注意BigDecimal的用法。由于浮点数和双精度数的准确性失败,因此对于货币计算始终必须使用这种或类似的方法。您可以转换为Long或Integer并自己跟踪缩放,但您将执行与BigDecimal类相同的操作。
您的解决方案很棒。我从来没有想过我可以那样做,谢谢您,先生!
还有一个问题,让每种货币拥有自己的汇率是一个好主意吗?将它们分开以便更好地更新它们会更好吗?
不确定数据的开头是什么,但是如果对数据进行排序,您应该具有货币组。您将永远必须先找到一种货币,然后再找到另一种。如果将所有货币都放入一个集合中,那么基本上就是一对汇率。是否取决于您的实际模型。例如,一家银行可能支持某种货币,而另一家银行可能支持另一种货币。因此,您可以进行银行分类并在其中添加Set货币。
@ k-nicholas嗯。我已经成功地构建了自己的解决方案,并以此为模板。我的问题是:为了使设置逻辑起作用,除了覆盖"等于"和" hashCode"方法之外,我还需要做其他事情吗?假设我要执行搜索,是否必须调用" hashCode()"? (PS:直到这个项目,我还没有碰过集和散列)
新问题应该是新职位。 stackoverflow.com/questions/5396939/
实际上,肯特·贝克(Kent Beck)在其有关TDD的书中就致力于解决此问题。
我没有读到最后,但我记得在某个时候他有Money抽象类,Sum(或类似的东西)来存放钱和Bank。银行负责货币汇率。
我不确定创建类似Dollar和Euro的类是否是一个好方法。也许坚持使用Money并将货币保留在实例变量(KISS)中可能会更加容易。我想我希望一种类别(Bank,ExchangeRate或最适合您的任何一种)完全处理货币,并使Money实例不可变。而且所有的计算都是由Sum类进行的(或其他任何方法,关键是要使逻辑远离金钱本身)。
无论如何,也许您应该只看一下贝克的书。我敢肯定他的设计很好。
这不能为问题提供答案。要批评或要求作者澄清,请在其帖子下方发表评论。 -来自评论
@DavidMaze>我也想听听您的一般设计。
我非常感谢您的解释。我将尝试您建议的方法,并看如何适合我的情况。这不是一个真正的项目,它只是我正在从事的个人项目。
java人民币换欧元_关于java:用于存储货币汇率的设计相关推荐
- java人民币换欧元_java – PdfBox编码符号货币欧元
不幸的是,PDFBox的字符串编码远非完美(版本1.8.x).不幸的是,它在编码通用PDF对象中的字符串时使用相同的例程,就像在内容流中编码字符串时一样,这是根本错误的.因此,您必须自己转换为正确的编 ...
- java一键换壁纸_【Java】Java批量下载必应壁纸工具
[Java] 纯文本查看 复制代码package com.ren; import java.io.BufferedOutputStream; import java.io.File; import j ...
- java项目----教务管理系统_基于Java的教务管理系统
java项目----教务管理系统_基于Java的教务管理系统 2022-04-22 18:18·java基础 最近为客户开发了一套学校用教务管理系统,主要实现学生.课程.老师.选课等相关的信息化管理功 ...
- java是什么格式_是java格式
错误:编码GBK的不可映射字符的解决办法 最近在重新补javaSE的基础,编辑器编写完代码以后,在控制台运行代码段的时候,出现了以下的错误提示:错误:编码GBK的不可映射字符 在通过查询谷哥和度娘以后 ...
- java语言程序设计答案_《java语言程序设计》练习题及答案
<java语言程序设计>练习题及答案 JAVA 语言程序设计题及部分答案 一.单选题:(每题1分)下列各题A).B).C).D)四个选项中, 只有一个选项是正确的,请将正确选项的标记写在题 ...
- java ee开发环境_设置Java EE 6开发环境
java ee开发环境 本教程简要说明了如何设置典型的环境来开发基于Java EE 6的应用程序. 除了可以正常工作的Windows XP客户端具有足够的CPU能力和内存外,本教程没有其他先决条件. ...
- java runnable线程锁_多线程 java 同步 、锁 、 synchronized 、 Thread 、 Runnable
线程 1 线程概述 1.1 什么是线程 v 线程是程序执行的一条路径, 一个进程中可以包含多条线程 v 一个应用程序可以理解成就是一个进程 v 多线程并发执行可以提高程序的效率, 可以同时完成多 ...
- java编程基础码_【Java编程的逻辑】编程基础
数据类型和变量 数据类型用于对数据归类,以便于理解和操做. - 整数类型:byte/short/int/long, 分别有不一样的取值范围 - 小数类型:float/double,有不一样的取值范围和 ...
- JAVA redis缓存过期_失效java服务器
Java 并发/多线程教程--4并发模型 本系列译自jakob jenkov的Java并发多线程教程(本章节部分内容参考http://ifeve.com/并发编程模型),个人觉得很有收获.由于个人水平 ...
最新文章
- java swing中英文支持,java - Swing国际化 - 如何在运行时更新语言 - SO中文参考 - www.soinside.com...
- CRUX下实现进程隐藏(3)
- Python装饰器-装饰流程,执行顺序
- 第二次作业 郭昭杰 201731062608
- base64的php文件上传,PHP传统文件上传和Base64位文件上传
- 2011年全国大学生程序设计邀请赛(福州)
- 光纤收发器和光电转换器有什么区别?
- 错误记录--更改tomcat端口号方法,Several ports (8005, 8080, 8009)
- 输出国际象棋输出余弦曲线
- mybatis中resultType取出数据顺序不一致解决方法
- BRD、MRD 和 PRD 之间的区别与联系有哪些?
- 从零学javascript_我刚刚问了23,000个开发人员他们对JavaScript的看法。 这是我学到的。...
- iPhone 13系列或将涨价?业内人士:可能性不大,原因有这几点
- 北京豪宅市场调查:多项目集中放量使选择面加大
- HDU3032_NimOrNotNim解题报告
- “Kindle App中文字体9MB下载失败”解决办法
- 计算机ps计划,ps教学计划
- 异常解决 java.lang.UnsupportedOperationException: Required method destroyItem was not overridden
- ADC转换速率kSPS定义
- springboot no tests were found
热门文章
- 总结一个老网站数据搬家注意事项
- android toast居中显示_android Toast 弹出在屏幕中间位置以及自定义Toast
- 用余弦定理求三角形内角
- tsm2812通用定时器中断_基于TMS320F2812的双通道高精度伺服系统
- python制作文字识别_用Python轻松进行图像文本识别
- 极光推送服务器端文档,Android SDK 集成指南
- 根据系统日期,判断输出该月份所属的季节(春、夏、秋、冬)
- java某公司运维管理系统
- 网络共享 指定的服务器无法运行请求的操作,局域网共享访问故障及解决方案...
- 浅谈分布式一致性算法raft