001/** 002 * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016package org.javamoney.moneta; 017 018import org.javamoney.moneta.ToStringMonetaryAmountFormat.ToStringMonetaryAmountFormatStyle; 019import org.javamoney.moneta.internal.FastMoneyAmountBuilder; 020import org.javamoney.moneta.spi.DefaultNumberValue; 021import org.javamoney.moneta.spi.MonetaryConfig; 022import org.javamoney.moneta.spi.MoneyUtils; 023 024import javax.money.*; 025import javax.money.format.MonetaryAmountFormat; 026 027import java.io.Serializable; 028import java.math.BigDecimal; 029import java.util.Objects; 030import java.util.logging.Level; 031import java.util.logging.Logger; 032 033/** 034 * <code>long</code> based implementation of {@link MonetaryAmount}.This class internally uses a 035 * single long number as numeric representation, which basically is interpreted as minor units.<p> 036 * It suggested to have a performance advantage of a 10-15 times faster compared to {@link Money}, 037 * which internally uses {@link BigDecimal}. Nevertheless this comes with a price of less precision. 038 * As an example performing the following calculation one million times, results in slightly 039 * different results: 040 * </p> 041 * <pre><code> 042 * Money money1 = money1.add(Money.of(EURO, 1234567.3444)); 043 * money1 = money1.subtract(Money.of(EURO, 232323)); 044 * money1 = money1.multiply(3.4); 045 * money1 = money1.divide(5.456); 046 * </code></pre> 047 * <p> 048 * Executed one million (1000000) times this results in {@code EUR 1657407.962529182}, calculated in 049 * 3680 ms, or roughly 3ns/loop. 050 * <p> 051 * whereas 052 * </p> 053 * <pre><code> 054 * FastMoney money1 = money1.add(FastMoney.of(EURO, 1234567.3444)); 055 * money1 = money1.subtract(FastMoney.of(EURO, 232323)); 056 * money1 = money1.multiply(3.4); 057 * money1 = money1.divide(5.456); 058 * </code></pre> 059 * <p> 060 * executed one million (1000000) times results in {@code EUR 1657407.96251}, calculated in 179 ms, 061 * which is less than 1ns/loop. 062 * </p><p> 063 * Also note than mixing up types my drastically change the performance behavior. E.g. replacing the 064 * code above with the following: * 065 * </p> 066 * <pre><code> 067 * FastMoney money1 = money1.add(Money.of(EURO, 1234567.3444)); 068 * money1 = money1.subtract(FastMoney.of(EURO, 232323)); 069 * money1 = money1.multiply(3.4); 070 * money1 = money1.divide(5.456); 071 * </code></pre> 072 * <p> 073 * executed one million (1000000) times may execute significantly longer, since monetary amount type 074 * conversion is involved. 075 * </p><p> 076 * Basically, when mixing amount implementations, the performance of the amount, on which most of 077 * the operations are operated, has the most significant impact on the overall performance behavior. 078 * 079 * @author Anatole Tresch 080 * @author Werner Keil 081 * @version 0.5.2 082 */ 083public final class FastMoney implements MonetaryAmount, Comparable<MonetaryAmount>, Serializable{ 084 085 private static final long serialVersionUID = 1L; 086 087 /** 088 * The currency of this amount. 089 */ 090 private final CurrencyUnit currency; 091 092 /** 093 * The numeric part of this amount. 094 */ 095 private final long number; 096 097 /** 098 * The current scale represented by the number. 099 */ 100 private static final int SCALE = 5; 101 102 /** 103 * the {@link MonetaryContext} used by this instance, e.g. on division. 104 */ 105 private static final MonetaryContext MONETARY_CONTEXT = 106 MonetaryContextBuilder.of(FastMoney.class).setMaxScale(SCALE).setFixedScale(true).setPrecision(19).build(); 107 /** 108 * Default rounding context used. 109 */ 110 // private static final MathContext CALC_CONTEXT = new MathContext(19, RoundingMode.HALF_EVEN); 111 112 /** 113 * Maximum possible value supported, using XX (no currency). 114 */ 115 public static final FastMoney MAX_VALUE = new FastMoney(Long.MAX_VALUE, MonetaryCurrencies.getCurrency("XXX")); 116 /** 117 * Maximum possible numeric value supported. 118 */ 119 private static final BigDecimal MAX_BD = MAX_VALUE.getBigDecimal(); 120 /** 121 * Minimum possible value supported, using XX (no currency). 122 */ 123 public static final FastMoney MIN_VALUE = new FastMoney(Long.MIN_VALUE, MonetaryCurrencies.getCurrency("XXX")); 124 /** 125 * Minimum possible numeric value supported. 126 */ 127 private static final BigDecimal MIN_BD = MIN_VALUE.getBigDecimal(); 128 129 130 /** 131 * Creates a new instance os {@link FastMoney}. 132 * 133 * @param currency the currency, not null. 134 * @param number the amount, not null. 135 */ 136 private FastMoney(Number number, CurrencyUnit currency, boolean allowInternalRounding){ 137 Objects.requireNonNull(currency, "Currency is required."); 138 this.currency = currency; 139 Objects.requireNonNull(number, "Number is required."); 140 this.number = getInternalNumber(number, allowInternalRounding); 141 } 142 143 /** 144 * Creates a new instance os {@link FastMoney}. 145 * 146 * @param currency the currency, not null. 147 * @param numberValue the numeric value, not null. 148 */ 149 private FastMoney(NumberValue numberValue, CurrencyUnit currency, boolean allowInternalRounding){ 150 Objects.requireNonNull(currency, "Currency is required."); 151 this.currency = currency; 152 Objects.requireNonNull(numberValue, "Number is required."); 153 this.number = getInternalNumber(numberValue.numberValue(BigDecimal.class), allowInternalRounding); 154 } 155 156 /** 157 * Creates a new instance os {@link FastMoney}. 158 * 159 * @param number The internal number value 160 * @param currency the currency, not null. 161 */ 162 private FastMoney(long number, CurrencyUnit currency){ 163 Objects.requireNonNull(currency, "Currency is required."); 164 this.currency = currency; 165 this.number = number; 166 } 167 168 /** 169 * Returns the amount’s currency, modelled as {@link CurrencyUnit}. 170 * Implementations may co-variantly change the return type to a more 171 * specific implementation of {@link CurrencyUnit} if desired. 172 * 173 * @return the currency, never {@code null} 174 * @see javax.money.MonetaryAmount#getCurrency() 175 */ 176 @Override 177 public CurrencyUnit getCurrency(){ 178 return currency; 179 } 180 181 /** 182 * Access the {@link MonetaryContext} used by this instance. 183 * 184 * @return the {@link MonetaryContext} used, never null. 185 * @see javax.money.MonetaryAmount#getMonetaryContext() 186 */ 187 @Override 188 public MonetaryContext getMonetaryContext(){ 189 return MONETARY_CONTEXT; 190 } 191 192 private long getInternalNumber(Number number, boolean allowInternalRounding){ 193 BigDecimal bd = MoneyUtils.getBigDecimal(number); 194 if(!allowInternalRounding && bd.scale() > SCALE){ 195 throw new ArithmeticException(number + " can not be represented by this class, scale > " + SCALE); 196 } 197 if(bd.compareTo(MIN_BD) < 0){ 198 throw new ArithmeticException("Overflow: " + number + " < " + MIN_BD); 199 }else if(bd.compareTo(MAX_BD) > 0){ 200 throw new ArithmeticException("Overflow: " + number + " > " + MAX_BD); 201 } 202 return bd.movePointRight(SCALE).longValue(); 203 } 204 205 206 /** 207 * Static factory method for creating a new instance of {@link FastMoney}. 208 * 209 * @param currency The target currency, not null. 210 * @param numberBinding The numeric part, not null. 211 * @return A new instance of {@link FastMoney}. 212 */ 213 public static FastMoney of(NumberValue numberBinding, CurrencyUnit currency){ 214 return new FastMoney(numberBinding, currency, false); 215 } 216 217 /** 218 * Static factory method for creating a new instance of {@link FastMoney}. 219 * 220 * @param currency The target currency, not null. 221 * @param number The numeric part, not null. 222 * @return A new instance of {@link FastMoney}. 223 */ 224 public static FastMoney of(Number number, CurrencyUnit currency){ 225 return new FastMoney(number, currency, false); 226 } 227 228 /** 229 * Static factory method for creating a new instance of {@link FastMoney}. 230 * 231 * @param currencyCode The target currency as currency code. 232 * @param number The numeric part, not null. 233 * @return A new instance of {@link FastMoney}. 234 */ 235 public static FastMoney of(Number number, String currencyCode){ 236 CurrencyUnit currency = MonetaryCurrencies.getCurrency(currencyCode); 237 return of(number, currency); 238 } 239 240 /* 241 * @see java.lang.Comparable#compareTo(java.lang.Object) 242 */ 243 @Override 244 public int compareTo(MonetaryAmount o){ 245 Objects.requireNonNull(o); 246 int compare = getCurrency().getCurrencyCode().compareTo(o.getCurrency().getCurrencyCode()); 247 if(compare == 0){ 248 compare = getNumber().numberValue(BigDecimal.class).compareTo(o.getNumber().numberValue(BigDecimal.class)); 249 } 250 return compare; 251 } 252 253 /* 254 * (non-Javadoc) 255 * @see java.lang.Object#hashCode() 256 */ 257 @Override 258 public int hashCode(){ 259 return Objects.hash(currency, number); 260 } 261 262 /* 263 * (non-Javadoc) 264 * @see java.lang.Object#equals(java.lang.Object) 265 */ 266 @Override 267 public boolean equals(Object obj){ 268 if(obj == this){ 269 return true; 270 } 271 if(obj instanceof FastMoney){ 272 FastMoney other = (FastMoney) obj; 273 return Objects.equals(currency, other.currency) && Objects.equals(number, other.number); 274 } 275 return false; 276 } 277 278 279 /* 280 * (non-Javadoc) 281 * @see javax.money.MonetaryAmount#abs() 282 */ 283 @Override 284 public FastMoney abs(){ 285 if(this.isPositiveOrZero()){ 286 return this; 287 } 288 return this.negate(); 289 } 290 291 // Arithmetic Operations 292 293 /* 294 * (non-Javadoc) 295 * @see javax.money.MonetaryAmount#add(javax.money.MonetaryAmount) 296 */ 297 @Override 298 public FastMoney add(MonetaryAmount amount){ 299 checkAmountParameter(amount); 300 if(amount.isZero()){ 301 return this; 302 } 303 return new FastMoney(Math.addExact(this.number, getInternalNumber(amount.getNumber(), false)), getCurrency()); 304 } 305 306 private void checkAmountParameter(MonetaryAmount amount){ 307 MoneyUtils.checkAmountParameter(amount, this.currency); 308 // numeric check for overflow... 309 if(amount.getNumber().getScale() > SCALE){ 310 throw new ArithmeticException("Parameter exceeds maximal scale: " + SCALE); 311 } 312 if(amount.getNumber().getPrecision() > MAX_BD.precision()){ 313 throw new ArithmeticException("Parameter exceeds maximal precision: " + SCALE); 314 } 315 } 316 317 318 /* 319 * (non-Javadoc) 320 * @see javax.money.MonetaryAmount#divide(java.lang.Number) 321 */ 322 @Override 323 public FastMoney divide(Number divisor){ 324 checkNumber(divisor); 325 if(isOne(divisor)){ 326 return this; 327 } 328 return new FastMoney(Math.round(this.number / divisor.doubleValue()), getCurrency()); 329 } 330 331 /* 332 * (non-Javadoc) 333 * @see javax.money.MonetaryAmount#divideAndRemainder(java.lang.Number) 334 */ 335 @Override 336 public FastMoney[] divideAndRemainder(Number divisor){ 337 checkNumber(divisor); 338 if(isOne(divisor)){ 339 return new FastMoney[]{this, FastMoney.of(0, getCurrency())}; 340 } 341 BigDecimal div = MoneyUtils.getBigDecimal(divisor); 342 BigDecimal[] res = getBigDecimal().divideAndRemainder(div); 343 return new FastMoney[]{new FastMoney(res[0], getCurrency(), true), new FastMoney(res[1], getCurrency(), true)}; 344 } 345 346 /* 347 * (non-Javadoc) 348 * @see javax.money.MonetaryAmount#divideToIntegralValue(java.lang.Number) 349 */ 350 @Override 351 public FastMoney divideToIntegralValue(Number divisor){ 352 checkNumber(divisor); 353 if(isOne(divisor)){ 354 return this; 355 } 356 BigDecimal div = MoneyUtils.getBigDecimal(divisor); 357 return new FastMoney(getBigDecimal().divideToIntegralValue(div), getCurrency(), false); 358 } 359 360 @Override 361 public FastMoney multiply(Number multiplicand){ 362 checkNumber(multiplicand); 363 if(isOne(multiplicand)){ 364 return this; 365 } 366 return new FastMoney(Math.round(this.number * multiplicand.doubleValue()), getCurrency()); 367 // BigDecimal mult = MoneyUtils.getBigDecimal(multiplicand); 368 // return new FastMoney(mult.multiply(BigDecimal.valueOf(this.number), 369 // CALC_CONTEXT).longValueExact(), getCurrency()); 370 } 371 372 /* 373 * (non-Javadoc) 374 * @see javax.money.MonetaryAmount#negate() 375 */ 376 @Override 377 public FastMoney negate(){ 378 return new FastMoney(this.number * -1, getCurrency()); 379 } 380 381 /* 382 * (non-Javadoc) 383 * @see javax.money.MonetaryAmount#plus() 384 */ 385 @Override 386 public FastMoney plus(){ 387 if(this.number >= 0){ 388 return this; 389 } 390 return new FastMoney(this.number * -1, getCurrency()); 391 } 392 393 /* 394 * (non-Javadoc) 395 * @see javax.money.MonetaryAmount#subtract(javax.money.MonetaryAmount) 396 */ 397 @Override 398 public FastMoney subtract(MonetaryAmount subtrahend){ 399 checkAmountParameter(subtrahend); 400 if(subtrahend.isZero()){ 401 return this; 402 } 403 long subtrahendAsLong = getInternalNumber(subtrahend.getNumber(), false); 404 return new FastMoney(Math.addExact(this.number, -1L * subtrahendAsLong), getCurrency()); 405 } 406 407 /* 408 * (non-Javadoc) 409 * @see javax.money.MonetaryAmount#remainder(java.lang.Number) 410 */ 411 @Override 412 public FastMoney remainder(Number divisor){ 413 checkNumber(divisor); 414 if(isOne(divisor)){ 415 return new FastMoney(0, getCurrency()); 416 } 417 return new FastMoney(this.number % getInternalNumber(divisor, true), getCurrency()); 418 } 419 420 private boolean isOne(Number number){ 421 BigDecimal bd = MoneyUtils.getBigDecimal(number); 422 try{ 423 return bd.scale() == 0 && bd.longValueExact() == 1L; 424 } 425 catch(Exception e){ 426 // The only way to end up here is that longValueExact throws an ArithmeticException, 427 // so the amount is definitively not equal to 1. 428 return false; 429 } 430 } 431 432 /* 433 * (non-Javadoc) 434 * @see javax.money.MonetaryAmount#scaleByPowerOfTen(int) 435 */ 436 @Override 437 public FastMoney scaleByPowerOfTen(int n){ 438 return new FastMoney(getNumber().numberValue(BigDecimal.class).scaleByPowerOfTen(n), getCurrency(), true); 439 } 440 441 /* 442 * (non-Javadoc) 443 * @see javax.money.MonetaryAmount#isZero() 444 */ 445 @Override 446 public boolean isZero(){ 447 return this.number == 0L; 448 } 449 450 /* 451 * (non-Javadoc) 452 * @see javax.money.MonetaryAmount#isPositive() 453 */ 454 @Override 455 public boolean isPositive(){ 456 return this.number > 0L; 457 } 458 459 /* 460 * (non-Javadoc) 461 * @see javax.money.MonetaryAmount#isPositiveOrZero() 462 */ 463 @Override 464 public boolean isPositiveOrZero(){ 465 return this.number >= 0L; 466 } 467 468 /* 469 * (non-Javadoc) 470 * @see javax.money.MonetaryAmount#isNegative() 471 */ 472 @Override 473 public boolean isNegative(){ 474 return this.number < 0L; 475 } 476 477 /* 478 * (non-Javadoc) 479 * @see javax.money.MonetaryAmount#isNegativeOrZero() 480 */ 481 @Override 482 public boolean isNegativeOrZero(){ 483 return this.number <= 0L; 484 } 485 486 /* 487 * (non-Javadoc) 488 * @see javax.money.MonetaryAmount#getScale() 489 */ 490 public int getScale(){ 491 return FastMoney.SCALE; 492 } 493 494 /* 495 * (non-Javadoc) 496 * @see javax.money.MonetaryAmount#getPrecision() 497 */ 498 public int getPrecision(){ 499 return getNumber().numberValue(BigDecimal.class).precision(); 500 } 501 502 /* 503 * (non-Javadoc) 504 * @see javax.money.MonetaryAmount#signum() 505 */ 506 507 @Override 508 public int signum(){ 509 if(this.number < 0){ 510 return -1; 511 } 512 if(this.number == 0){ 513 return 0; 514 } 515 return 1; 516 } 517 518 /* 519 * (non-Javadoc) 520 * @see javax.money.MonetaryAmount#lessThan(javax.money.MonetaryAmount) 521 */ 522 @Override 523 public boolean isLessThan(MonetaryAmount amount){ 524 checkAmountParameter(amount); 525 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) < 0; 526 } 527 528 /* 529 * (non-Javadoc) 530 * @see javax.money.MonetaryAmount#lessThan(java.lang.Number) 531 */ 532 public boolean isLessThan(Number number){ 533 checkNumber(number); 534 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) < 0; 535 } 536 537 /* 538 * (non-Javadoc) 539 * @see javax.money.MonetaryAmount#lessThanOrEqualTo(javax.money.MonetaryAmount) 540 */ 541 @Override 542 public boolean isLessThanOrEqualTo(MonetaryAmount amount){ 543 checkAmountParameter(amount); 544 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) <= 0; 545 } 546 547 /* 548 * (non-Javadoc) 549 * @see javax.money.MonetaryAmount#lessThanOrEqualTo(java.lang.Number) 550 */ 551 public boolean isLessThanOrEqualTo(Number number){ 552 checkNumber(number); 553 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) <= 0; 554 } 555 556 /* 557 * (non-Javadoc) 558 * @see javax.money.MonetaryAmount#greaterThan(javax.money.MonetaryAmount) 559 */ 560 @Override 561 public boolean isGreaterThan(MonetaryAmount amount){ 562 checkAmountParameter(amount); 563 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) > 0; 564 } 565 566 /* 567 * (non-Javadoc) 568 * @see javax.money.MonetaryAmount#greaterThan(java.lang.Number) 569 */ 570 public boolean isGreaterThan(Number number){ 571 checkNumber(number); 572 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) > 0; 573 } 574 575 /* 576 * (non-Javadoc) 577 * @see javax.money.MonetaryAmount#greaterThanOrEqualTo(javax.money.MonetaryAmount ) #see 578 */ 579 @Override 580 public boolean isGreaterThanOrEqualTo(MonetaryAmount amount){ 581 checkAmountParameter(amount); 582 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) >= 0; 583 } 584 585 /* 586 * (non-Javadoc) 587 * @see javax.money.MonetaryAmount#greaterThanOrEqualTo(java.lang.Number) 588 */ 589 public boolean isGreaterThanOrEqualTo(Number number){ 590 checkNumber(number); 591 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) >= 0; 592 } 593 594 /* 595 * (non-Javadoc) 596 * @see javax.money.MonetaryAmount#isEqualTo(javax.money.MonetaryAmount) 597 */ 598 @Override 599 public boolean isEqualTo(MonetaryAmount amount){ 600 checkAmountParameter(amount); 601 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) == 0; 602 } 603 604 /* 605 * (non-Javadoc) 606 * @see javax.money.MonetaryAmount#hasSameNumberAs(java.lang.Number) 607 */ 608 public boolean hasSameNumberAs(Number number){ 609 checkNumber(number); 610 try{ 611 return this.number == getInternalNumber(number, false); 612 } 613 catch(ArithmeticException e){ 614 return false; 615 } 616 } 617 618 619 /** 620 * Gets the number representation of the numeric value of this item. 621 * 622 * @return The {@link Number} represention matching best. 623 */ 624 @Override 625 public NumberValue getNumber(){ 626 return new DefaultNumberValue(getBigDecimal()); 627 } 628 629 @Override 630 public String toString(){ 631 return currency.toString() + ' ' + getBigDecimal(); 632 } 633 634 // Internal helper methods 635 636 /** 637 * Internal method to check for correct number parameter. 638 * 639 * @param number the number to be checked, including null.. 640 * @throws NullPointerException If the number is null 641 * @throws java.lang.ArithmeticException If the number exceeds the capabilities of this class. 642 */ 643 protected void checkNumber(Number number){ 644 Objects.requireNonNull(number, "Number is required."); 645 // numeric check for overflow... 646 if(number.longValue() > MAX_BD.longValue()){ 647 throw new ArithmeticException("Value exceeds maximal value: " + MAX_BD); 648 } 649 BigDecimal bd = MoneyUtils.getBigDecimal(number); 650 if(bd.precision() > MAX_BD.precision()){ 651 throw new ArithmeticException("Precision exceeds maximal precision: " + MAX_BD.precision()); 652 } 653 if(bd.scale() > SCALE){ 654 if(Boolean.parseBoolean(MonetaryConfig.getConfig() 655 .getOrDefault("org.javamoney.moneta.FastMoney.enforceScaleCompatibility", 656 "false"))){ 657 throw new ArithmeticException("Scale of " + bd + " exceeds maximal scale: " + SCALE); 658 }else{ 659 Logger log = Logger.getLogger(getClass().getName()); 660 if(log.isLoggable(Level.FINEST)){ 661 log.finest("Scale exceeds maximal scale of FastMoney (" + SCALE + 662 "), implicit rounding will be applied to " + number); 663 } 664 } 665 } 666 } 667 668 /* 669 * }(non-Javadoc) 670 * @see javax.money.MonetaryAmount#adjust(javax.money.AmountAdjuster) 671 */ 672 @Override 673 public FastMoney with(MonetaryOperator operator){ 674 Objects.requireNonNull(operator); 675 try{ 676 return FastMoney.class.cast(operator.apply(this)); 677 } 678 catch(ArithmeticException e){ 679 throw e; 680 } 681 catch(Exception e){ 682 throw new MonetaryException("Operator failed: " + operator, e); 683 } 684 } 685 686 @Override 687 public <R> R query(MonetaryQuery<R> query){ 688 Objects.requireNonNull(query); 689 try{ 690 return query.queryFrom(this); 691 } 692 catch(MonetaryException | ArithmeticException e){ 693 throw e; 694 } 695 catch(Exception e){ 696 throw new MonetaryException("Query failed: " + query, e); 697 } 698 } 699 700 public static FastMoney from(MonetaryAmount amount){ 701 if (FastMoney.class.isInstance(amount)) { 702 return FastMoney.class.cast(amount); 703 } 704 return new FastMoney(amount.getNumber(), amount.getCurrency(), false); 705 } 706 707 /** 708 * Obtains an instance of FastMoney from a text string such as 'EUR 25.25'. 709 * @param text the text to parse not null 710 * @return FastMoney instance 711 * @throws NullPointerException 712 * @throws NumberFormatException 713 * @throws UnknownCurrencyException 714 */ 715 public static FastMoney parse(CharSequence text) { 716 return parse(text, DEFAULT_FORMATTER); 717 } 718 /** 719 * Obtains an instance of FastMoney from a text using specific formatter. 720 * @param text the text to parse not null 721 * @param formatter the formatter to use not null 722 * @return FastMoney instance 723 */ 724 public static FastMoney parse(CharSequence text, MonetaryAmountFormat formatter) { 725 return from(formatter.parse(text)); 726 } 727 728 private static ToStringMonetaryAmountFormat DEFAULT_FORMATTER = ToStringMonetaryAmountFormat 729 .of(ToStringMonetaryAmountFormatStyle.FAST_MONEY); 730 731 private BigDecimal getBigDecimal(){ 732 return BigDecimal.valueOf(this.number).movePointLeft(SCALE); 733 } 734 735 @Override 736 public FastMoney multiply(double amount){ 737 if(amount == 1.0){ 738 return this; 739 } 740 if(amount == 0.0){ 741 return new FastMoney(0, this.currency); 742 } 743 return new FastMoney(Math.round(this.number * amount), this.currency); 744 } 745 746 @Override 747 public FastMoney divide(long amount){ 748 if(amount == 1L){ 749 return this; 750 } 751 return new FastMoney(this.number / amount, this.currency); 752 } 753 754 @Override 755 public FastMoney divide(double number){ 756 if(number == 1.0d){ 757 return this; 758 } 759 return new FastMoney(Math.round(this.number / number), getCurrency()); 760 } 761 762 @Override 763 public FastMoney remainder(long number){ 764 return remainder(BigDecimal.valueOf(number)); 765 } 766 767 @Override 768 public FastMoney remainder(double amount){ 769 return remainder(new BigDecimal(String.valueOf(amount))); 770 } 771 772 @Override 773 public FastMoney[] divideAndRemainder(long amount){ 774 return divideAndRemainder(BigDecimal.valueOf(amount)); 775 } 776 777 @Override 778 public FastMoney[] divideAndRemainder(double amount){ 779 return divideAndRemainder(new BigDecimal(String.valueOf(amount))); 780 } 781 782 @Override 783 public FastMoney stripTrailingZeros(){ 784 return this; 785 } 786 787 @Override 788 public FastMoney multiply(long multiplicand){ 789 if(multiplicand == 1){ 790 return this; 791 } 792 if(multiplicand == 0){ 793 return new FastMoney(0L, this.currency); 794 } 795 return new FastMoney(multiplicand * this.number, this.currency); 796 } 797 798 @Override 799 public FastMoney divideToIntegralValue(long divisor){ 800 if(divisor == 1){ 801 return this; 802 } 803 return divideToIntegralValue(MoneyUtils.getBigDecimal(divisor)); 804 } 805 806 @Override 807 public FastMoney divideToIntegralValue(double divisor){ 808 if(divisor == 1.0){ 809 return this; 810 } 811 return divideToIntegralValue(MoneyUtils.getBigDecimal(divisor)); 812 } 813 814 @Override 815 public MonetaryAmountFactory<FastMoney> getFactory(){ 816 return new FastMoneyAmountBuilder().setAmount(this); 817 } 818 819}