如何在Java中为大量资金建模
有人能推荐一个能为大量资金建模的类库或设计模式吗 我想它应该支持:如何在Java中为大量资金建模,java,design-patterns,model,modeling,Java,Design Patterns,Model,Modeling,有人能推荐一个能为大量资金建模的类库或设计模式吗 我想它应该支持: 多种货币 表示小数位数的一种机制 数学(关于某些舍入约定(cfr ie)) 与字符串表示形式之间的序列化 也就是说,19.99美元可以序列化为“USD-2000-0000000 1999” (2表示小数位数)这似乎有帮助,但我没有这方面的经验:Joda money看起来也很有希望: (不知道生产准备得如何)我会检查项目中的模块(由Jean-Marie Dautelle编写) 根据您的具体需求,Stephen Colebou
- 多种货币
- 表示小数位数的一种机制
- 数学(关于某些舍入约定(cfr ie))
- 与字符串表示形式之间的序列化
- 李>
(2表示小数位数)这似乎有帮助,但我没有这方面的经验:Joda money看起来也很有希望: (不知道生产准备得如何)我会检查项目中的模块(由Jean-Marie Dautelle编写)
根据您的具体需求,Stephen Colebourne不久前开始了(“一个比JScience更专注的项目”)。但是目前还没有完整的版本(0.5版是一年前发布的)。除了Paul所说的,还有Martin Fowler的。JSR 354 JavaMoney应该成为Java 9的一部分。 查看更多细节 这个JSR应该是Joda Money的替代品,但目前只有Joda Money是稳定的,并在生产中经过测试 您还可以查看以下库:
- JSScience-使用货币单位
- (“需要alpha用户”)
package com.console.utils.value;
import com.console.core.exceptions.UnknownCurrencyCodeException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.Currency;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.Assert;
import static java.math.RoundingMode.HALF_UP;
/**
*
* @author farouka
*/
public class Money implements Serializable {
/**
* Why me
*/
private static final int[] cents = new int[]{1, 10, 100, 1000};
private BigDecimal amount;
private Currency currency;
//private MathContext DEFAULT_CONTEXT = new MathContext( 2, HALF_UP );
private MathContext DEFAULT_CONTEXT = new MathContext( 10, RoundingMode.HALF_DOWN );
public Money(long amount, Currency currency) {
this.currency = currency;
this.amount = BigDecimal.valueOf(amount, currency.getDefaultFractionDigits());
}
/**
* Creates a currency object from the long value provided assuming the long value
* represents the base currency in the least monetary unit. For eg, new Money(500, "GBP")
* is assumed to mean 5.00 great british pounds
* @param amount in base monetary unit
* @param currCode
* @throws com.console.core.exceptions.UnknownCurrencyCodeException
*/
public Money(long amount, String currCode) throws UnknownCurrencyCodeException {
this( amount, Currency.getInstance(currCode) );
}
/**
* Construct an IMMUTABLE money object from a double. It is assumed that
* the whole part of the double is the Money with the fractional part representing
* lowest denominator of the currency. For eg, new Money (50.99, "GBP") is assumed
* to be 50 pounds and 99 pence.
* PS. 89.788 will be truncated to 89.78 based on the defaultcurrencydigit of the currency
* @param amount
* @param curr
*/
public Money(double amount, Currency curr) {
this.currency = curr;
BigDecimal bd = BigDecimal.valueOf( amount );
this.amount = bd.setScale(centFactor(), HALF_UP);
}
private Money() {
}
/**
* Construct an IMMUTABLE money object from a double. It is assumed that
* the whole part of the double is the Money with the fractional part representing
* lowest denominator of the currency. For eg, new Money (50.99, "GBP") is assumed
* to be 50 pounds and 99 pence.
* PS. 89.788 will be truncated to 89.78 based on the defaultcurrencydigit of the currency
* code supplied
* @param amount
* @param currCode iso 4217 currency code
* @throws com.console.core.exceptions.UnknownCurrencyCodeException
*/
public Money(double amount, String currCode) throws UnknownCurrencyCodeException {
this.currency = Currency.getInstance(currCode);
BigDecimal bd = BigDecimal.valueOf( amount );
this.amount = bd.setScale( currency.getDefaultFractionDigits(), HALF_UP);
}
/**
* Constructs an IMMUTABLE money from a BigDecimal. the BigDecimal provided is only scaled
* to used the default digits in currency object represented by the sting parameter
* @param bigDecimal
* @param currCode ISO 4217 cuurency code
* @throws com.console.core.exceptions.UnknownCurrencyCodeException
*/
public Money(BigDecimal bigDecimal, String currCode ) throws UnknownCurrencyCodeException {
this.currency = Currency.getInstance(currCode);
this.amount = bigDecimal.setScale( currency.getDefaultFractionDigits(), HALF_UP);
}
/**
* Constructs an IMMUTABLE money from a BigDecimal. the BigDecimal provided is only scaled
* to used the default digits in currency object represented by the sting parameter
* @param multiply
* @param currency
*/
public Money(BigDecimal bigDecimal, Currency currency) {
this.currency = currency;
this.amount = bigDecimal.setScale( currency.getDefaultFractionDigits(), HALF_UP);
}
// public boolean assertSameCurrencyAs(Money arg) {
// return this.currency.getCurrencyCode().equals(arg.currency.getCurrencyCode());
// }
//
public boolean assertSameCurrencyAs(Money money) throws IncompatibleCurrencyException{
if ( this.currency == null ) {
throw new IncompatibleCurrencyException( "currency.invalid" );
}
if ( money == null ) {
throw new IncompatibleCurrencyException( "currency.invalid" );
}
Assert.assertEquals("money math mismatch", currency, money.currency);
return true;
}
private int centFactor() {
return cents[ getCurrency().getDefaultFractionDigits() ];
}
public BigDecimal amount() {
return amount;
}
public long amountAsLong(){
return amount.unscaledValue().longValue();
}
public Currency getCurrency() {
return currency;
}
// common currencies
public static Money dollars(double amount) {
Money result = null;
try {
result = new Money(amount, "USD");
} catch (UnknownCurrencyCodeException ex) {
Logger.getLogger(Money.class.getName()).log(Level.SEVERE, null, ex);
}
return result;
}
public static Money dollars(long amount) {
Money result = null;
try {
result = new Money(amount, "USD");
} catch (UnknownCurrencyCodeException ex) {
Logger.getLogger(Money.class.getName()).log(Level.SEVERE, null, ex);
}
return result;
}
public static Money pounds(double amount) {
Money result = null;
try {
result = new Money(amount, "GBP");
} catch (UnknownCurrencyCodeException ex) {
Logger.getLogger(Money.class.getName()).log(Level.SEVERE, null, ex);
}
return result;
}
public static Money pounds(long amount) {
Money result = null;
try {
result = new Money(amount, "GBP");
} catch (UnknownCurrencyCodeException ex) {
Logger.getLogger(Money.class.getName()).log(Level.SEVERE, null, ex);
}
return result;
}
public static Money pounds(BigDecimal amount) {
Money result = null;
try {
result = new Money(amount, "GBP");
} catch (UnknownCurrencyCodeException ex) {
Logger.getLogger(Money.class.getName()).log(Level.SEVERE, null, ex);
}
return result;
}
@Override
public int hashCode() {
int hash = (int) ( amount.hashCode() ^ (amount.hashCode() >>> 32) );
return hash;
}
@Override
public boolean equals(Object other) {
return (other instanceof Money && equals((Money) other));
}
public boolean equals(Money other) {
return ( currency.equals(other.currency) && (amount.equals(other.amount)) );
}
public Money add(Money other) throws Exception{
assertSameCurrencyAs( other );
return newMoney(amount.add(other.amount, DEFAULT_CONTEXT));
}
private int compareTo(Money money) throws Exception {
assertSameCurrencyAs( money );
return amount.compareTo( money.amount );
}
public Money multiply(BigDecimal amount) {
return new Money( this.amount().multiply(amount, DEFAULT_CONTEXT), currency);
}
public Money multiply( BigDecimal amount, RoundingMode roundingMode ) {
MathContext ct = new MathContext( currency.getDefaultFractionDigits(), roundingMode );
return new Money( amount().multiply(amount, ct), currency);
}
private Money newMoney(BigDecimal amount) {
return new Money( amount, this.currency );
}
public Money multiply(double amount) {
return multiply( new BigDecimal( amount ) );
}
public Money subtract(Money other) throws Exception {
assertSameCurrencyAs(other);
return newMoney( amount.subtract(other.amount, DEFAULT_CONTEXT) );
}
public int compareTo(Object other) throws Exception {
return compareTo((Money) other);
}
public boolean greaterThan(Money other)throws Exception {
return (compareTo(other) > 0);
}
// public Money[] allocate(int n){
// Money lowResult = newMoney( amount.unscaledValue().longValue()/n );
// Money highResult = newMoney(lowResult.amount + 1);
// Money[] results = new Money[n];
// int remainder = (int) amount % n;
//
// for(int i = 0; i < remainder; i++)results[i] = highResult;
// for(int i = 0; i < n; i++) results[i] = lowResult;
//
// return results;
// }
//
// public Money[]allocate(long[] ratios){
// long total = 0;
// for (int i = 0; i < ratios.length; i++) {
// total += ratios[i];
// }
// long remainder = amount;
// Money[] results = new Money[ratios.length];
// for (int i = 0; i < results.length; i++) {
// results[i] = newMoney(amount * ratios[i]/total);
// remainder -= results[i].amount;
// }
// for (int i = 0; i < remainder; i++) {
// results[i].amount++;
// }
// return results;
//
// }
public Money divideByNumber( double divisor){
BigDecimal div = BigDecimal.valueOf( divisor );
BigDecimal ans = this.amount.divide(div, DEFAULT_CONTEXT);
return new Money(ans, this.currency);
}
public int getQuotient( Money divisor ){
BigDecimal ans = this.amount.divide(divisor.amount, RoundingMode.DOWN);
return ans.intValue();
}
/**
* divides toe moneys and return the quotient and Remainder this method has been customised,
* for my money transfer needs...sorry
* @param divisor
* @return
*/
public int[] getQuotientandRemainder(Money divisor){
int[] ans = new int[2];
BigDecimal[] bdArr = this.amount.divideAndRemainder(divisor.amount, DEFAULT_CONTEXT);
BigDecimal quo = bdArr[0];
BigDecimal rem = bdArr[1];
ans[0] = quo.intValue();
if( rem.compareTo(BigDecimal.ZERO) == 0 ){
ans[1] =0;
}else{
ans[1] = 1;
}
return ans;
}
public String toFormattedString() {
NumberFormat nf = NumberFormat.getCurrencyInstance();
nf.setCurrency( currency );
nf.setGroupingUsed( true );
nf.setMaximumFractionDigits( currency.getDefaultFractionDigits() );
return nf.format( this.amount.doubleValue() );
}
/**
* Returns the ISO-4217 currency code of the currency
* attached to this money.
*
* @return The ISO-4217 currency code.
*/
public String getCurrencyCode() {
return currency.getCurrencyCode();
}
@Override
public String toString() {
return amount.toString();
}
/**
* Returns the precision for this money. The precision is the total number
* of digits that the value can represent. This includes the integer part.
* So, 18 would be able to represent:
*
* 1234567890.12345678
*
* 1234567890123456.78
*
* 123456789012345678
*
* 0.123456789012345678
*
* @return The precision.
*/
public int precision() {
return amount.precision();
}
/**
* Returns the 'scale' for this money. The scale is the number of
* digits that are moved to the fractional part, assuming that all
* digits are represented by a single integer value. For example:
*
* If: 123456789012345678 has scaling 2, it would be :
*
* 1234567890123456.78
*
* @return The scale value.
*/
public int scale() {
return amount.scale();
}
/**
* Returns the sign for the money (negative or positive).
* -1 if negative, 0 if 0.00 (zero), 1 if positive.
*
* @return The sign of the money.
*/
public int signum() {
return amount.signum();
}
}
And here is the UnknownCurrencyCodeException class
package com.console.lib.utils;
/**
* An exception which is raised when an unrecognised currency code is passed to the
* Currency class.
*
* @author Farouk Alhassan
* @see Currency
*/
public class UnknownCurrencyCodeException extends Exception {
// Reason for exception
private String reason = null;
/**
* Create a new unknown currency code exception.
*
* @param reason for the exception
*/
public UnknownCurrencyCodeException(String reason) {
this.reason = reason;
}
/**
* Return the reason this exception was raised.
*
* @return the reason why the string isn't a valid currency code
*/
public String getReason() {
return reason;
}
/**
* Convert the exception to a string
*
* @return string version of the exception
*/
public String toString() {
return getReason();
}
}
package com.console.utils.value;
导入com.console.core.exceptions.UnknownCurrencyCodeException;
导入java.io.Serializable;
导入java.math.BigDecimal;
导入java.math.MathContext;
导入java.math.RoundingMode;
导入java.text.NumberFormat;
导入java.util.Currency;
导入java.util.logging.Level;
导入java.util.logging.Logger;
导入org.junit.Assert;
导入静态java.math.RoundingMode.HALF_UP;
/**
*
*@作者法鲁卡
*/
公共类货币实现可序列化{
/**
*为什么是我
*/
私有静态最终整数[]分=新整数[]{1,10,100,1000};
私人金额;
私人货币;
//private MathContext DEFAULT_CONTEXT=新MathContext(2,一半以上);
private MathContext DEFAULT_CONTEXT=新MathContext(10,RoundingMode.HALF_DOWN);
公共资金(长期金额、货币){
这个。货币=货币;
this.amount=BigDecimal.valueOf(amount,currency.getDefaultFractionDigits());
}
/**
*根据提供的long值(假定为long值)创建货币对象
*表示以最小货币单位表示的基础货币。例如,新货币(500,“英镑”)
*假设是指5.00英镑
*@param以基本货币单位表示的金额
*@param currCode
*@throws com.console.core.exceptions.UnknownCurrencyCodeException
*/
公共资金(长金额,字符串currCode)抛出UnknownCurrencyCodeException{
这(金额、货币.getInstance(currCode));
}
/**
*从double构造一个不可变的money对象
*双精度的整个部分是货币,小数部分代表
*货币的最低分母。例如,假设新货币(50.99英镑)
*50磅99便士。
*根据货币的DefaultCurrencyDigital,PS.89.788将被截断为89.78
*@param金额
*@param curr
*/
公共资金(双倍金额,货币){
该货币=货币;
BigDecimal bd=BigDecimal.valueOf(金额);
this.amount=bd.setScale(centFactor(),向上减半);
}
私人资金{
}
/**
*从double构造一个不可变的money对象
*双精度的整个部分是货币,小数部分代表
*货币的最低分母。例如,假设新货币(50.99英镑)
*50磅99便士。
*根据货币的DefaultCurrencyDigital,PS.89.788将被截断为89.78
*提供的代码
*@param金额
*@param currCode iso 4217货币代码
*@throws com.console.core.exceptions.UnknownCurrencyCodeException
*/
公共资金(双倍金额,字符串currCode)引发UnknownCurrencyCodeException{
this.currency=currency.getInstance(currCode);
BigDecimal bd=BigDecimal.valueOf(金额);
this.amount=bd.setScale(currency.getDefaultFractionDigits(),上半个);
}
/**
*从BigDecimal构造不可变货币。提供的BigDecimal仅按比例缩放
*使用sting参数表示的货币对象中的默认数字
*@param bigDecimal
*@param currCode ISO 4217 CUURENCE代码
*@throws com.console.core.exceptions.UnknownCurrencyCodeException
*/
公共货币(BigDecimal BigDecimal,字符串currCode)抛出UnknownCurrencyCodeException{
this.currency=currency.getInstance(currCode);
this.amount=bigDecimal.setScale(currency.getDefaultFractionDigits(),向上减半);
}
/**
*从BigDecimal构造不可变货币。提供的BigDecimal仅按比例缩放
*使用sting参数表示的货币对象中的默认数字
*@param乘法
*@param货币
*/
公共货币(BigDecimal BigDecimal,货币){
这个。货币=货币;
this.amount=bigDecimal.setScale(currency.getDefaultFractionDigits(),向上减半);
}
//公共布尔资产samecurrencyas(货币参数){
//返回此.currency.getCurrencyCode().equals(arg.currency.getCurrencyCode());
// }
//
公共布尔资产Samecurrencyas(Money Money)抛出不兼容的CurrencyException{
如果(this.currency==null){
抛出新的不兼容CurrencyException(“currency.invalid”);
}
if(money==null){
抛出新的不兼容CurrencyException(“currency.invalid”);
}
Assert.assertEquals(“货币数学不匹配”,货币,货币,货币);
返回true;