1 /* 2 * Copyright 2009-2013 Stephen Colebourne 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.joda.money; 17 18 import java.io.InvalidObjectException; 19 import java.io.ObjectInputStream; 20 import java.io.Serializable; 21 import java.math.BigDecimal; 22 import java.math.BigInteger; 23 import java.math.RoundingMode; 24 import java.util.Arrays; 25 import java.util.Iterator; 26 import java.util.regex.Pattern; 27 28 import org.joda.convert.FromString; 29 import org.joda.convert.ToString; 30 31 /** 32 * An amount of money with unrestricted decimal place precision. 33 * <p> 34 * This class represents a quantity of money, stored as a {@code BigDecimal} amount 35 * in a single {@link CurrencyUnit currency}. 36 * <p> 37 * Every currency has a certain standard number of decimal places. 38 * This is typically 2 (Euro, British Pound, US Dollar) but might be 39 * 0 (Japanese Yen), 1 (Vietnamese Dong) or 3 (Bahrain Dinar). 40 * The {@code BigMoney} class is not restricted to the standard decimal places 41 * and can represent an amount to any precision that a {@code BigDecimal} can represent. 42 * <p> 43 * This class is immutable and thread-safe. 44 */ 45 public final class BigMoney implements BigMoneyProvider, Comparable<BigMoneyProvider>, Serializable { 46 47 /** 48 * The serialisation version. 49 */ 50 private static final long serialVersionUID = 1L; 51 /** 52 * The regex for parsing. 53 */ 54 private static final Pattern PARSE_REGEX = Pattern.compile("[+-]?[0-9]*[.]?[0-9]*"); 55 56 /** 57 * The currency, not null. 58 */ 59 private final CurrencyUnit currency; 60 /** 61 * The amount, not null. 62 */ 63 private final BigDecimal amount; 64 65 //----------------------------------------------------------------------- 66 /** 67 * Obtains an instance of {@code BigMoney} from a {@code BigDecimal}. 68 * <p> 69 * This allows you to create an instance with a specific currency and amount. 70 * The scale of the money will be that of the BigDecimal. 71 * 72 * @param currency the currency, not null 73 * @param amount the amount of money, not null 74 * @return the new instance, never null 75 * @throws IllegalArgumentException if an invalid BigDecimal subclass has been used 76 */ 77 public static BigMoney of(CurrencyUnit currency, BigDecimal amount) { 78 MoneyUtils.checkNotNull(currency, "Currency must not be null"); 79 MoneyUtils.checkNotNull(amount, "Amount must not be null"); 80 if (amount.getClass() != BigDecimal.class) { 81 BigInteger value = amount.unscaledValue(); 82 if (value == null) { 83 throw new IllegalArgumentException("Illegal BigDecimal subclass"); 84 } 85 if (value.getClass() != BigInteger.class) { 86 value = new BigInteger(value.toString()); 87 } 88 amount = new BigDecimal(value, amount.scale()); 89 } 90 return new BigMoney(currency, amount); 91 } 92 93 /** 94 * Obtains an instance of {@code BigMoney} from a {@code double} using a well-defined conversion. 95 * <p> 96 * This allows you to create an instance with a specific currency and amount. 97 * <p> 98 * The amount is converted via {@link BigDecimal#valueOf(double)} which yields 99 * the most expected answer for most programming scenarios. 100 * Any {@code double} literal in code will be converted to 101 * exactly the same BigDecimal with the same scale. 102 * For example, the literal '1.425d' will be converted to '1.425'. 103 * The scale of the money will be that of the BigDecimal produced. 104 * 105 * @param currency the currency, not null 106 * @param amount the amount of money, not null 107 * @return the new instance, never null 108 */ 109 public static BigMoney of(CurrencyUnit currency, double amount) { 110 MoneyUtils.checkNotNull(currency, "Currency must not be null"); 111 return BigMoney.of(currency, BigDecimal.valueOf(amount)); 112 } 113 114 //----------------------------------------------------------------------- 115 /** 116 * Obtains an instance of {@code BigMoney} from a {@code BigDecimal} at a specific scale. 117 * <p> 118 * This allows you to create an instance with a specific currency and amount. 119 * No rounding is performed on the amount, so it must have a 120 * scale less than or equal to the new scale. 121 * 122 * @param currency the currency, not null 123 * @param amount the amount of money, not null 124 * @param scale the scale to use, zero or positive 125 * @return the new instance, never null 126 * @throws ArithmeticException if the scale exceeds the currency scale 127 */ 128 public static BigMoney ofScale(CurrencyUnit currency, BigDecimal amount, int scale) { 129 return BigMoney.ofScale(currency, amount, scale, RoundingMode.UNNECESSARY); 130 } 131 132 /** 133 * Obtains an instance of {@code BigMoney} from a {@code double} using a 134 * well-defined conversion, rounding as necessary. 135 * <p> 136 * This allows you to create an instance with a specific currency and amount. 137 * If the amount has a scale in excess of the scale of the currency then the excess 138 * fractional digits are rounded using the rounding mode. 139 * 140 * @param currency the currency, not null 141 * @param amount the amount of money, not null 142 * @param scale the scale to use, zero or positive 143 * @param roundingMode the rounding mode to use, not null 144 * @return the new instance, never null 145 * @throws ArithmeticException if the rounding fails 146 */ 147 public static BigMoney ofScale(CurrencyUnit currency, BigDecimal amount, int scale, RoundingMode roundingMode) { 148 MoneyUtils.checkNotNull(currency, "CurrencyUnit must not be null"); 149 MoneyUtils.checkNotNull(amount, "Amount must not be null"); 150 MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null"); 151 amount = amount.setScale(scale, roundingMode); 152 return BigMoney.of(currency, amount); 153 } 154 155 /** 156 * Obtains an instance of {@code BigMoney} from a scaled amount. 157 * <p> 158 * This allows you to create an instance with a specific currency, amount and scale. 159 * The amount is defined in terms of the specified scale. 160 * <p> 161 * For example, {@code ofScale(USD, 234, 2)} creates the instance {@code USD 2.34}. 162 * 163 * @param currency the currency, not null 164 * @param unscaledAmount the unscaled amount of money 165 * @param scale the scale to use 166 * @return the new instance, never null 167 */ 168 public static BigMoney ofScale(CurrencyUnit currency, long unscaledAmount, int scale) { 169 MoneyUtils.checkNotNull(currency, "Currency must not be null"); 170 return BigMoney.of(currency, BigDecimal.valueOf(unscaledAmount, scale)); 171 } 172 173 //----------------------------------------------------------------------- 174 /** 175 * Obtains an instance of {@code BigMoney} from an amount in major units. 176 * <p> 177 * This allows you to create an instance with a specific currency and amount. 178 * The scale of the money will be zero. 179 * <p> 180 * The amount is a whole number only. Thus you can initialise the value 181 * 'USD 20', but not the value 'USD 20.32'. 182 * For example, {@code ofMajor(USD, 25)} creates the instance {@code USD 25}. 183 * 184 * @param currency the currency, not null 185 * @param amountMajor the amount of money in the major division of the currency 186 * @return the new instance, never null 187 */ 188 public static BigMoney ofMajor(CurrencyUnit currency, long amountMajor) { 189 MoneyUtils.checkNotNull(currency, "CurrencyUnit must not be null"); 190 return BigMoney.of(currency, BigDecimal.valueOf(amountMajor)); 191 } 192 193 /** 194 * Obtains an instance of {@code BigMoney} from an amount in minor units. 195 * <p> 196 * This allows you to create an instance with a specific currency and amount 197 * expressed in terms of the minor unit. 198 * The scale of the money will be that of the currency, such as 2 for USD or 0 for JPY. 199 * <p> 200 * For example, if constructing US Dollars, the input to this method represents cents. 201 * Note that when a currency has zero decimal places, the major and minor units are the same. 202 * For example, {@code ofMajor(USD, 2595)} creates the instance {@code USD 25.95}. 203 * 204 * @param currency the currency, not null 205 * @param amountMinor the amount of money in the minor division of the currency 206 * @return the new instance, never null 207 */ 208 public static BigMoney ofMinor(CurrencyUnit currency, long amountMinor) { 209 MoneyUtils.checkNotNull(currency, "CurrencyUnit must not be null"); 210 return BigMoney.of(currency, BigDecimal.valueOf(amountMinor, currency.getDecimalPlaces())); 211 } 212 213 //----------------------------------------------------------------------- 214 /** 215 * Obtains an instance of {@code BigMoney} representing zero. 216 * <p> 217 * The scale of the money will be zero. 218 * For example, {@code zero(USD)} creates the instance {@code USD 0}. 219 * 220 * @param currency the currency, not null 221 * @return the instance representing zero, never null 222 */ 223 public static BigMoney zero(CurrencyUnit currency) { 224 return BigMoney.of(currency, BigDecimal.ZERO); 225 } 226 227 /** 228 * Obtains an instance of {@code BigMoney} representing zero at a specific scale. 229 * <p> 230 * For example, {@code zero(USD, 2)} creates the instance {@code USD 0.00}. 231 * 232 * @param currency the currency, not null 233 * @param scale the scale to use, zero or positive 234 * @return the instance representing zero, never null 235 * @throws IllegalArgumentException if the scale is negative 236 */ 237 public static BigMoney zero(CurrencyUnit currency, int scale) { 238 return BigMoney.of(currency, BigDecimal.valueOf(0, scale)); 239 } 240 241 //----------------------------------------------------------------------- 242 /** 243 * Obtains an instance of {@code BigMoney} from a provider. 244 * <p> 245 * This allows you to create an instance from any class that implements the 246 * provider, such as {@code Money}. 247 * This method simply calls {@link BigMoneyProvider#toBigMoney()} checking for nulls. 248 * 249 * @param moneyProvider the money to convert, not null 250 * @return the new instance, never null 251 */ 252 public static BigMoney of(BigMoneyProvider moneyProvider) { 253 MoneyUtils.checkNotNull(moneyProvider, "BigMoneyProvider must not be null"); 254 BigMoney money = moneyProvider.toBigMoney(); 255 MoneyUtils.checkNotNull(money, "BigMoneyProvider must not return null"); 256 return money; 257 } 258 259 //----------------------------------------------------------------------- 260 /** 261 * Obtains an instance of {@code BigMoney} as the total value of an array. 262 * <p> 263 * The array must contain at least one monetary value. 264 * Subsequent amounts are added as though using {@link #plus(BigMoneyProvider)}. 265 * All amounts must be in the same currency. 266 * 267 * @param monies the monetary values to total, not empty, no null elements, not null 268 * @return the total, never null 269 * @throws IllegalArgumentException if the array is empty 270 * @throws CurrencyMismatchException if the currencies differ 271 */ 272 public static BigMoney total(BigMoneyProvider... monies) { 273 MoneyUtils.checkNotNull(monies, "Money array must not be null"); 274 if (monies.length == 0) { 275 throw new IllegalArgumentException("Money array must not be empty"); 276 } 277 BigMoney total = of(monies[0]); 278 MoneyUtils.checkNotNull(total, "Money arary must not contain null entries"); 279 for (int i = 1; i < monies.length; i++) { 280 total = total.plus(of(monies[i])); 281 } 282 return total; 283 } 284 285 /** 286 * Obtains an instance of {@code BigMoney} as the total value of a collection. 287 * <p> 288 * The iterable must provide at least one monetary value. 289 * Subsequent amounts are added as though using {@link #plus(BigMoneyProvider)}. 290 * All amounts must be in the same currency. 291 * 292 * @param monies the monetary values to total, not empty, no null elements, not null 293 * @return the total, never null 294 * @throws IllegalArgumentException if the iterable is empty 295 * @throws CurrencyMismatchException if the currencies differ 296 */ 297 public static BigMoney total(Iterable<? extends BigMoneyProvider> monies) { 298 MoneyUtils.checkNotNull(monies, "Money iterator must not be null"); 299 Iterator<? extends BigMoneyProvider> it = monies.iterator(); 300 if (it.hasNext() == false) { 301 throw new IllegalArgumentException("Money iterator must not be empty"); 302 } 303 BigMoney total = of(it.next()); 304 MoneyUtils.checkNotNull(total, "Money iterator must not contain null entries"); 305 while (it.hasNext()) { 306 total = total.plus(it.next()); 307 } 308 return total; 309 } 310 311 /** 312 * Obtains an instance of {@code Money} as the total value of 313 * a possibly empty array. 314 * <p> 315 * The amounts are added as though using {@link #plus(BigMoneyProvider)} starting 316 * from zero in the specified currency. 317 * All amounts must be in the same currency. 318 * 319 * @param currency the currency to total in, not null 320 * @param monies the monetary values to total, no null elements, not null 321 * @return the total, never null 322 * @throws CurrencyMismatchException if the currencies differ 323 */ 324 public static BigMoney total(CurrencyUnit currency, BigMoneyProvider... monies) { 325 return BigMoney.zero(currency).plus(Arrays.asList(monies)); 326 } 327 328 /** 329 * Obtains an instance of {@code Money} as the total value of 330 * a possibly empty collection. 331 * <p> 332 * The amounts are added as though using {@link #plus(BigMoneyProvider)} starting 333 * from zero in the specified currency. 334 * All amounts must be in the same currency. 335 * 336 * @param currency the currency to total in, not null 337 * @param monies the monetary values to total, no null elements, not null 338 * @return the total, never null 339 * @throws CurrencyMismatchException if the currencies differ 340 */ 341 public static BigMoney total(CurrencyUnit currency, Iterable<? extends BigMoneyProvider> monies) { 342 return BigMoney.zero(currency).plus(monies); 343 } 344 345 //----------------------------------------------------------------------- 346 /** 347 * Parses an instance of {@code BigMoney} from a string. 348 * <p> 349 * The string format is '<currencyCode> <amount>'. 350 * The currency code must be a valid three letter currency. 351 * The amount must match the regular expression {@code [+-]?[0-9]*[.]?[0-9]*}. 352 * This matches the output from {@link #toString()}. 353 * <p> 354 * For example, {@code parse("USD 25")} creates the instance {@code USD 25} 355 * while {@code parse("USD 25.95")} creates the instance {@code USD 25.95}. 356 * 357 * @param moneyStr the money string to parse, not null 358 * @return the parsed instance, never null 359 * @throws IllegalArgumentException if the string is malformed 360 * @throws ArithmeticException if the amount is too large 361 */ 362 @FromString 363 public static BigMoney parse(String moneyStr) { 364 MoneyUtils.checkNotNull(moneyStr, "Money must not be null"); 365 if (moneyStr.length() < 5 || moneyStr.charAt(3) != ' ') { 366 throw new IllegalArgumentException("Money '" + moneyStr + "' cannot be parsed"); 367 } 368 String currStr = moneyStr.substring(0, 3); 369 String amountStr = moneyStr.substring(4); 370 if (PARSE_REGEX.matcher(amountStr).matches() == false) { 371 throw new IllegalArgumentException("Money amount '" + moneyStr + "' cannot be parsed"); 372 } 373 return BigMoney.of(CurrencyUnit.of(currStr), new BigDecimal(amountStr)); 374 } 375 376 //----------------------------------------------------------------------- 377 /** 378 * Ensures that a {@code BigMoney} is not {@code null}. 379 * <p> 380 * If the input money is not {@code null}, then it is returned, providing 381 * that the currency matches the specified currency. 382 * If the input money is {@code null}, then zero money in the currency 383 * is returned with a scale of zero. 384 * 385 * @param money the monetary value to check, may be null 386 * @param currency the currency to use, not null 387 * @return the input money or zero in the specified currency, never null 388 * @throws CurrencyMismatchException if the input money is non-null and the currencies differ 389 */ 390 public static BigMoney nonNull(BigMoney money, CurrencyUnit currency) { 391 if (money == null) { 392 return zero(currency); 393 } 394 if (money.getCurrencyUnit().equals(currency) == false) { 395 MoneyUtils.checkNotNull(currency, "Currency must not be null"); 396 throw new CurrencyMismatchException(money.getCurrencyUnit(), currency); 397 } 398 return money; 399 } 400 401 //----------------------------------------------------------------------- 402 /** 403 * Constructor, creating a new monetary instance. 404 * 405 * @param currency the currency to use, not null 406 * @param amount the amount of money, not null 407 */ 408 BigMoney(CurrencyUnit currency, BigDecimal amount) { 409 assert currency != null : "Joda-Money bug: Currency must not be null"; 410 assert amount != null : "Joda-Money bug: Amount must not be null"; 411 this.currency = currency; 412 this.amount = amount; 413 } 414 415 /** 416 * Block malicious data streams. 417 * 418 * @param ois the input stream, not null 419 * @throws InvalidObjectException 420 */ 421 private void readObject(ObjectInputStream ois) throws InvalidObjectException { 422 throw new InvalidObjectException("Serialization delegate required"); 423 } 424 425 /** 426 * Uses a serialization delegate. 427 * 428 * @return the replacing object, never null 429 */ 430 private Object writeReplace() { 431 return new Ser(Ser.BIG_MONEY, this); 432 } 433 434 //----------------------------------------------------------------------- 435 /** 436 * Returns a new {@code BigMoney}, returning {@code this} if possible. 437 * <p> 438 * This instance is immutable and unaffected by this method. 439 * 440 * @param newAmount the new amount to use, not null 441 * @return the new instance, never null 442 */ 443 private BigMoney with(BigDecimal newAmount) { 444 if (newAmount == amount) { 445 return this; 446 } 447 return new BigMoney(currency, newAmount); 448 } 449 450 //----------------------------------------------------------------------- 451 /** 452 * Gets the currency. 453 * 454 * @return the currency, never null 455 */ 456 public CurrencyUnit getCurrencyUnit() { 457 return currency; 458 } 459 460 //----------------------------------------------------------------------- 461 /** 462 * Returns a copy of this monetary value with the specified currency. 463 * <p> 464 * The returned instance will have the specified currency and the amount 465 * from this instance. No currency conversion or alteration to the scale occurs. 466 * <p> 467 * This instance is immutable and unaffected by this method. 468 * 469 * @param currency the currency to use, not null 470 * @return the new instance with the input currency set, never null 471 */ 472 public BigMoney withCurrencyUnit(CurrencyUnit currency) { 473 MoneyUtils.checkNotNull(currency, "CurrencyUnit must not be null"); 474 if (this.currency == currency) { 475 return this; 476 } 477 return new BigMoney(currency, amount); 478 } 479 480 //----------------------------------------------------------------------- 481 /** 482 * Gets the scale of the {@code BigDecimal} amount. 483 * <p> 484 * The scale has the same meaning as in {@link BigDecimal}. 485 * Positive values represent the number of decimal places in use. 486 * Negative numbers represent the opposite. 487 * For example, a scale of 2 means that the money will have two decimal places 488 * such as 'USD 43.25'. Whereas, a scale of -3 means that only thousands can be 489 * represented, such as 'GBP 124000'. 490 * 491 * @return the scale in use 492 * @see #withScale 493 */ 494 public int getScale() { 495 return amount.scale(); 496 } 497 498 /** 499 * Checks if this money has the scale of the currency. 500 * <p> 501 * Each currency has a default scale, such as 2 for USD and 0 for JPY. 502 * This method checks if the current scale matches the default scale. 503 * 504 * @return true if the scale equals the current default scale 505 */ 506 public boolean isCurrencyScale() { 507 return amount.scale() == currency.getDecimalPlaces(); 508 } 509 510 //----------------------------------------------------------------------- 511 /** 512 * Returns a copy of this monetary value with the specified scale, 513 * truncating the amount if necessary. 514 * <p> 515 * The returned instance will have this currency and the new scaled amount. 516 * For example, scaling 'USD 43.271' to a scale of 1 will yield 'USD 43.2'. 517 * No rounding is performed on the amount, so it must have a 518 * scale less than or equal to the new scale. 519 * <p> 520 * This instance is immutable and unaffected by this method. 521 * 522 * @param scale the scale to use 523 * @return the new instance with the input amount set, never null 524 * @throws ArithmeticException if the rounding fails 525 */ 526 public BigMoney withScale(int scale) { 527 return withScale(scale, RoundingMode.UNNECESSARY); 528 } 529 530 /** 531 * Returns a copy of this monetary value with the specified scale, 532 * using the specified rounding mode if necessary. 533 * <p> 534 * The returned instance will have this currency and the new scaled amount. 535 * For example, scaling 'USD 43.271' to a scale of 1 with HALF_EVEN rounding 536 * will yield 'USD 43.3'. 537 * <p> 538 * This instance is immutable and unaffected by this method. 539 * 540 * @param scale the scale to use 541 * @param roundingMode the rounding mode to use, not null 542 * @return the new instance with the input amount set, never null 543 * @throws ArithmeticException if the rounding fails 544 */ 545 public BigMoney withScale(int scale, RoundingMode roundingMode) { 546 MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null"); 547 if (scale == amount.scale()) { 548 return this; 549 } 550 return BigMoney.of(currency, amount.setScale(scale, roundingMode)); 551 } 552 553 //----------------------------------------------------------------------- 554 /** 555 * Returns a copy of this monetary value with the scale of the currency, 556 * truncating the amount if necessary. 557 * <p> 558 * The returned instance will have this currency and the new scaled amount. 559 * For example, scaling 'USD 43.271' will yield 'USD 43.27' as USD has a scale of 2. 560 * No rounding is performed on the amount, so it must have a 561 * scale less than or equal to the new scale. 562 * <p> 563 * This instance is immutable and unaffected by this method. 564 * 565 * @return the new instance with the input amount set, never null 566 * @throws ArithmeticException if the rounding fails 567 */ 568 public BigMoney withCurrencyScale() { 569 return withScale(currency.getDecimalPlaces(), RoundingMode.UNNECESSARY); 570 } 571 572 /** 573 * Returns a copy of this monetary value with the scale of the currency, 574 * using the specified rounding mode if necessary. 575 * <p> 576 * The returned instance will have this currency and the new scaled amount. 577 * For example, scaling 'USD 43.271' will yield 'USD 43.27' as USD has a scale of 2. 578 * <p> 579 * This instance is immutable and unaffected by this method. 580 * 581 * @param roundingMode the rounding mode to use, not null 582 * @return the new instance with the input amount set, never null 583 * @throws ArithmeticException if the rounding fails 584 */ 585 public BigMoney withCurrencyScale(RoundingMode roundingMode) { 586 return withScale(currency.getDecimalPlaces(), roundingMode); 587 } 588 589 //----------------------------------------------------------------------- 590 /** 591 * Gets the amount. 592 * <p> 593 * This returns the value of the money as a {@code BigDecimal}. 594 * The scale will be the scale of this money. 595 * 596 * @return the amount, never null 597 */ 598 public BigDecimal getAmount() { 599 return amount; 600 } 601 602 /** 603 * Gets the amount in major units as a {@code BigDecimal} with scale 0. 604 * <p> 605 * This returns the monetary amount in terms of the major units of the currency, 606 * truncating the amount if necessary. 607 * For example, 'EUR 2.35' will return 2, and 'BHD -1.345' will return -1. 608 * <p> 609 * This is returned as a {@code BigDecimal} rather than a {@code BigInteger}. 610 * This is to allow further calculations to be performed on the result. 611 * Should you need a {@code BigInteger}, simply call {@link BigDecimal#toBigInteger()}. 612 * 613 * @return the major units part of the amount, never null 614 */ 615 public BigDecimal getAmountMajor() { 616 return amount.setScale(0, RoundingMode.DOWN); 617 } 618 619 /** 620 * Gets the amount in major units as a {@code long}. 621 * <p> 622 * This returns the monetary amount in terms of the major units of the currency, 623 * truncating the amount if necessary. 624 * For example, 'EUR 2.35' will return 2, and 'BHD -1.345' will return -1. 625 * 626 * @return the major units part of the amount 627 * @throws ArithmeticException if the amount is too large for a {@code long} 628 */ 629 public long getAmountMajorLong() { 630 return getAmountMajor().longValueExact(); 631 } 632 633 /** 634 * Gets the amount in major units as an {@code int}. 635 * <p> 636 * This returns the monetary amount in terms of the major units of the currency, 637 * truncating the amount if necessary. 638 * For example, 'EUR 2.35' will return 2, and 'BHD -1.345' will return -1. 639 * 640 * @return the major units part of the amount 641 * @throws ArithmeticException if the amount is too large for an {@code int} 642 */ 643 public int getAmountMajorInt() { 644 return getAmountMajor().intValueExact(); 645 } 646 647 /** 648 * Gets the amount in minor units as a {@code BigDecimal} with scale 0. 649 * <p> 650 * This returns the monetary amount in terms of the minor units of the currency, 651 * truncating the amount if necessary. 652 * For example, 'EUR 2.35' will return 235, and 'BHD -1.345' will return -1345. 653 * <p> 654 * This is returned as a {@code BigDecimal} rather than a {@code BigInteger}. 655 * This is to allow further calculations to be performed on the result. 656 * Should you need a {@code BigInteger}, simply call {@link BigDecimal#toBigInteger()}. 657 * 658 * @return the minor units part of the amount, never null 659 */ 660 public BigDecimal getAmountMinor() { 661 int cdp = getCurrencyUnit().getDecimalPlaces(); 662 return amount.setScale(cdp, RoundingMode.DOWN).movePointRight(cdp); 663 } 664 665 /** 666 * Gets the amount in minor units as a {@code long}. 667 * <p> 668 * This returns the monetary amount in terms of the minor units of the currency, 669 * truncating the amount if necessary. 670 * For example, 'EUR 2.35' will return 235, and 'BHD -1.345' will return -1345. 671 * 672 * @return the minor units part of the amount 673 * @throws ArithmeticException if the amount is too large for a {@code long} 674 */ 675 public long getAmountMinorLong() { 676 return getAmountMinor().longValueExact(); 677 } 678 679 /** 680 * Gets the amount in minor units as an {@code int}. 681 * <p> 682 * This returns the monetary amount in terms of the minor units of the currency, 683 * truncating the amount if necessary. 684 * For example, 'EUR 2.35' will return 235, and 'BHD -1.345' will return -1345. 685 * 686 * @return the minor units part of the amount 687 * @throws ArithmeticException if the amount is too large for an {@code int} 688 */ 689 public int getAmountMinorInt() { 690 return getAmountMinor().intValueExact(); 691 } 692 693 /** 694 * Gets the minor part of the amount. 695 * <p> 696 * This return the minor unit part of the monetary amount. 697 * This is defined as the amount in minor units excluding major units. 698 * <p> 699 * For example, EUR has a scale of 2, so the minor part is always between 0 and 99 700 * for positive amounts, and 0 and -99 for negative amounts. 701 * Thus 'EUR 2.35' will return 35, and 'EUR -1.34' will return -34. 702 * 703 * @return the minor part of the amount, negative if the amount is negative 704 */ 705 public int getMinorPart() { 706 int cdp = getCurrencyUnit().getDecimalPlaces(); 707 return amount.setScale(cdp, RoundingMode.DOWN) 708 .remainder(BigDecimal.ONE) 709 .movePointRight(cdp).intValueExact(); 710 } 711 712 //----------------------------------------------------------------------- 713 /** 714 * Checks if the amount is zero. 715 * 716 * @return true if the amount is zero 717 */ 718 public boolean isZero() { 719 return amount.compareTo(BigDecimal.ZERO) == 0; 720 } 721 722 /** 723 * Checks if the amount is greater than zero. 724 * 725 * @return true if the amount is greater than zero 726 */ 727 public boolean isPositive() { 728 return amount.compareTo(BigDecimal.ZERO) > 0; 729 } 730 731 /** 732 * Checks if the amount is zero or greater. 733 * 734 * @return true if the amount is zero or greater 735 */ 736 public boolean isPositiveOrZero() { 737 return amount.compareTo(BigDecimal.ZERO) >= 0; 738 } 739 740 /** 741 * Checks if the amount is less than zero. 742 * 743 * @return true if the amount is less than zero 744 */ 745 public boolean isNegative() { 746 return amount.compareTo(BigDecimal.ZERO) < 0; 747 } 748 749 /** 750 * Checks if the amount is zero or less. 751 * 752 * @return true if the amount is zero or less 753 */ 754 public boolean isNegativeOrZero() { 755 return amount.compareTo(BigDecimal.ZERO) <= 0; 756 } 757 758 //----------------------------------------------------------------------- 759 /** 760 * Returns a copy of this monetary value with the specified amount. 761 * <p> 762 * The returned instance will have this currency and the new amount. 763 * The scale of the returned instance will be that of the specified BigDecimal. 764 * <p> 765 * This instance is immutable and unaffected by this method. 766 * 767 * @param amount the monetary amount to set in the returned instance, not null 768 * @return the new instance with the input amount set, never null 769 */ 770 public BigMoney withAmount(BigDecimal amount) { 771 MoneyUtils.checkNotNull(amount, "Amount must not be null"); 772 if (this.amount.equals(amount)) { 773 return this; 774 } 775 return BigMoney.of(currency, amount); 776 } 777 778 /** 779 * Returns a copy of this monetary value with the specified amount using a well-defined 780 * conversion from a {@code double}. 781 * <p> 782 * The returned instance will have this currency and the new amount. 783 * <p> 784 * The amount is converted via {@link BigDecimal#valueOf(double)} which yields 785 * the most expected answer for most programming scenarios. 786 * Any {@code double} literal in code will be converted to 787 * exactly the same BigDecimal with the same scale. 788 * For example, the literal '1.425d' will be converted to '1.425'. 789 * The scale of the money will be that of the BigDecimal produced. 790 * <p> 791 * This instance is immutable and unaffected by this method. 792 * 793 * @param amount the monetary amount to set in the returned instance 794 * @return the new instance with the input amount set, never null 795 */ 796 public BigMoney withAmount(double amount) { 797 return withAmount(BigDecimal.valueOf(amount)); 798 } 799 800 //----------------------------------------------------------------------- 801 /** 802 * Validates that the currency of this money and the specified money match. 803 * 804 * @param moneyProvider the money to check, not null 805 * @throws CurrencyMismatchException if the currencies differ 806 */ 807 private BigMoney checkCurrencyEqual(BigMoneyProvider moneyProvider) { 808 BigMoney money = of(moneyProvider); 809 if (isSameCurrency(money) == false) { 810 throw new CurrencyMismatchException(getCurrencyUnit(), money.getCurrencyUnit()); 811 } 812 return money; 813 } 814 815 //----------------------------------------------------------------------- 816 /** 817 * Returns a copy of this monetary value with a collection of monetary amounts added. 818 * <p> 819 * This adds the specified amounts to this monetary amount, returning a new object. 820 * The amounts are added as though using {@link #plus(BigMoneyProvider)}. 821 * The amounts must be in the same currency. 822 * <p> 823 * This instance is immutable and unaffected by this method. 824 * 825 * @param moniesToAdd the monetary values to add, no null elements, not null 826 * @return the new instance with the input amounts added, never null 827 * @throws CurrencyMismatchException if the currencies differ 828 */ 829 public BigMoney plus(Iterable<? extends BigMoneyProvider> moniesToAdd) { 830 BigDecimal total = amount; 831 for (BigMoneyProvider moneyProvider : moniesToAdd) { 832 BigMoney money = checkCurrencyEqual(moneyProvider); 833 total = total.add(money.amount); 834 } 835 return with(total); 836 } 837 838 //----------------------------------------------------------------------- 839 /** 840 * Returns a copy of this monetary value with the amount added. 841 * <p> 842 * This adds the specified amount to this monetary amount, returning a new object. 843 * The amount added must be in the same currency. 844 * <p> 845 * No precision is lost in the result. 846 * The scale of the result will be the maximum of the two scales. 847 * For example, 'USD 25.95' plus 'USD 3.021' gives 'USD 28.971'. 848 * <p> 849 * This instance is immutable and unaffected by this method. 850 * 851 * @param moneyToAdd the monetary value to add, not null 852 * @return the new instance with the input amount added, never null 853 * @throws CurrencyMismatchException if the currencies differ 854 */ 855 public BigMoney plus(BigMoneyProvider moneyToAdd) { 856 BigMoney toAdd = checkCurrencyEqual(moneyToAdd); 857 return plus(toAdd.getAmount()); 858 } 859 860 /** 861 * Returns a copy of this monetary value with the amount added. 862 * <p> 863 * This adds the specified amount to this monetary amount, returning a new object. 864 * <p> 865 * No precision is lost in the result. 866 * The scale of the result will be the maximum of the two scales. 867 * For example, 'USD 25.95' plus '3.021' gives 'USD 28.971'. 868 * <p> 869 * This instance is immutable and unaffected by this method. 870 * 871 * @param amountToAdd the monetary value to add, not null 872 * @return the new instance with the input amount added, never null 873 */ 874 public BigMoney plus(BigDecimal amountToAdd) { 875 MoneyUtils.checkNotNull(amountToAdd, "Amount must not be null"); 876 if (amountToAdd.compareTo(BigDecimal.ZERO) == 0) { 877 return this; 878 } 879 BigDecimal newAmount = amount.add(amountToAdd); 880 return BigMoney.of(currency, newAmount); 881 } 882 883 /** 884 * Returns a copy of this monetary value with the amount added. 885 * <p> 886 * This adds the specified amount to this monetary amount, returning a new object. 887 * <p> 888 * No precision is lost in the result. 889 * The scale of the result will be the maximum of the two scales. 890 * For example, 'USD 25.95' plus '3.021d' gives 'USD 28.971'. 891 * <p> 892 * The amount is converted via {@link BigDecimal#valueOf(double)} which yields 893 * the most expected answer for most programming scenarios. 894 * Any {@code double} literal in code will be converted to 895 * exactly the same BigDecimal with the same scale. 896 * For example, the literal '1.45d' will be converted to '1.45'. 897 * <p> 898 * This instance is immutable and unaffected by this method. 899 * 900 * @param amountToAdd the monetary value to add, not null 901 * @return the new instance with the input amount added, never null 902 */ 903 public BigMoney plus(double amountToAdd) { 904 if (amountToAdd == 0) { 905 return this; 906 } 907 BigDecimal newAmount = amount.add(BigDecimal.valueOf(amountToAdd)); 908 return BigMoney.of(currency, newAmount); 909 } 910 911 /** 912 * Returns a copy of this monetary value with the amount in major units added. 913 * <p> 914 * This adds the specified amount in major units to this monetary amount, 915 * returning a new object. The minor units will be untouched in the result. 916 * <p> 917 * No precision is lost in the result. 918 * The scale of the result will be the maximum of the current scale and 0. 919 * For example, 'USD 23.45' plus '138' gives 'USD 161.45'. 920 * <p> 921 * This instance is immutable and unaffected by this method. 922 * 923 * @param amountToAdd the monetary value to add, not null 924 * @return the new instance with the input amount added, never null 925 */ 926 public BigMoney plusMajor(long amountToAdd) { 927 if (amountToAdd == 0) { 928 return this; 929 } 930 BigDecimal newAmount = amount.add(BigDecimal.valueOf(amountToAdd)); 931 return BigMoney.of(currency, newAmount); 932 } 933 934 /** 935 * Returns a copy of this monetary value with the amount in minor units added. 936 * <p> 937 * This adds the specified amount in minor units to this monetary amount, 938 * returning a new object. 939 * <p> 940 * No precision is lost in the result. 941 * The scale of the result will be the maximum of the current scale and the default currency scale. 942 * For example, 'USD 23.45' plus '138' gives 'USD 24.83'. 943 * <p> 944 * This instance is immutable and unaffected by this method. 945 * 946 * @param amountToAdd the monetary value to add, not null 947 * @return the new instance with the input amount added, never null 948 */ 949 public BigMoney plusMinor(long amountToAdd) { 950 if (amountToAdd == 0) { 951 return this; 952 } 953 BigDecimal newAmount = amount.add(BigDecimal.valueOf(amountToAdd, currency.getDecimalPlaces())); 954 return BigMoney.of(currency, newAmount); 955 } 956 957 //----------------------------------------------------------------------- 958 /** 959 * Returns a copy of this monetary value with the amount in the same currency added 960 * retaining the scale by rounding the result. 961 * <p> 962 * The scale of the result will be the same as the scale of this instance. 963 * For example,'USD 25.95' plus 'USD 3.021' gives 'USD 28.97' with most rounding modes. 964 * <p> 965 * This instance is immutable and unaffected by this method. 966 * 967 * @param moneyToAdd the monetary value to add, not null 968 * @param roundingMode the rounding mode to use to adjust the scale, not null 969 * @return the new instance with the input amount added, never null 970 */ 971 public BigMoney plusRetainScale(BigMoneyProvider moneyToAdd, RoundingMode roundingMode) { 972 BigMoney toAdd = checkCurrencyEqual(moneyToAdd); 973 return plusRetainScale(toAdd.getAmount(), roundingMode); 974 } 975 976 /** 977 * Returns a copy of this monetary value with the amount added retaining 978 * the scale by rounding the result. 979 * <p> 980 * The scale of the result will be the same as the scale of this instance. 981 * For example,'USD 25.95' plus '3.021' gives 'USD 28.97' with most rounding modes. 982 * <p> 983 * This instance is immutable and unaffected by this method. 984 * 985 * @param amountToAdd the monetary value to add, not null 986 * @param roundingMode the rounding mode to use to adjust the scale, not null 987 * @return the new instance with the input amount added, never null 988 */ 989 public BigMoney plusRetainScale(BigDecimal amountToAdd, RoundingMode roundingMode) { 990 MoneyUtils.checkNotNull(amountToAdd, "Amount must not be null"); 991 if (amountToAdd.compareTo(BigDecimal.ZERO) == 0) { 992 return this; 993 } 994 BigDecimal newAmount = amount.add(amountToAdd); 995 newAmount = newAmount.setScale(getScale(), roundingMode); 996 return BigMoney.of(currency, newAmount); 997 } 998 999 /** 1000 * Returns a copy of this monetary value with the amount added retaining 1001 * the scale by rounding the result. 1002 * <p> 1003 * The scale of the result will be the same as the scale of this instance. 1004 * For example,'USD 25.95' plus '3.021d' gives 'USD 28.97' with most rounding modes. 1005 * <p> 1006 * The amount is converted via {@link BigDecimal#valueOf(double)} which yields 1007 * the most expected answer for most programming scenarios. 1008 * Any {@code double} literal in code will be converted to 1009 * exactly the same BigDecimal with the same scale. 1010 * For example, the literal '1.45d' will be converted to '1.45'. 1011 * <p> 1012 * This instance is immutable and unaffected by this method. 1013 * 1014 * @param amountToAdd the monetary value to add, not null 1015 * @param roundingMode the rounding mode to use to adjust the scale, not null 1016 * @return the new instance with the input amount added, never null 1017 */ 1018 public BigMoney plusRetainScale(double amountToAdd, RoundingMode roundingMode) { 1019 if (amountToAdd == 0) { 1020 return this; 1021 } 1022 BigDecimal newAmount = amount.add(BigDecimal.valueOf(amountToAdd)); 1023 newAmount = newAmount.setScale(getScale(), roundingMode); 1024 return BigMoney.of(currency, newAmount); 1025 } 1026 1027 //----------------------------------------------------------------------- 1028 /** 1029 * Returns a copy of this monetary value with a collection of monetary amounts subtracted. 1030 * <p> 1031 * This subtracts the specified amounts from this monetary amount, returning a new object. 1032 * The amounts are subtracted one by one as though using {@link #minus(BigMoneyProvider)}. 1033 * The amounts must be in the same currency. 1034 * <p> 1035 * This instance is immutable and unaffected by this method. 1036 * 1037 * @param moniesToSubtract the monetary values to subtract, no null elements, not null 1038 * @return the new instance with the input amounts subtracted, never null 1039 * @throws CurrencyMismatchException if the currencies differ 1040 */ 1041 public BigMoney minus(Iterable<? extends BigMoneyProvider> moniesToSubtract) { 1042 BigDecimal total = amount; 1043 for (BigMoneyProvider moneyProvider : moniesToSubtract) { 1044 BigMoney money = checkCurrencyEqual(moneyProvider); 1045 total = total.subtract(money.amount); 1046 } 1047 return with(total); 1048 } 1049 1050 //----------------------------------------------------------------------- 1051 /** 1052 * Returns a copy of this monetary value with the amount subtracted. 1053 * <p> 1054 * This subtracts the specified amount from this monetary amount, returning a new object. 1055 * The amount subtracted must be in the same currency. 1056 * <p> 1057 * No precision is lost in the result. 1058 * The scale of the result will be the maximum of the two scales. 1059 * For example,'USD 25.95' minus 'USD 3.021' gives 'USD 22.929'. 1060 * <p> 1061 * This instance is immutable and unaffected by this method. 1062 * 1063 * @param moneyToSubtract the monetary value to subtract, not null 1064 * @return the new instance with the input amount subtracted, never null 1065 * @throws CurrencyMismatchException if the currencies differ 1066 */ 1067 public BigMoney minus(BigMoneyProvider moneyToSubtract) { 1068 BigMoney toSubtract = checkCurrencyEqual(moneyToSubtract); 1069 return minus(toSubtract.getAmount()); 1070 } 1071 1072 /** 1073 * Returns a copy of this monetary value with the amount subtracted. 1074 * <p> 1075 * This subtracts the specified amount from this monetary amount, returning a new object. 1076 * <p> 1077 * No precision is lost in the result. 1078 * The scale of the result will be the maximum of the two scales. 1079 * For example,'USD 25.95' minus '3.021' gives 'USD 22.929'. 1080 * <p> 1081 * This instance is immutable and unaffected by this method. 1082 * 1083 * @param amountToSubtract the monetary value to subtract, not null 1084 * @return the new instance with the input amount subtracted, never null 1085 */ 1086 public BigMoney minus(BigDecimal amountToSubtract) { 1087 MoneyUtils.checkNotNull(amountToSubtract, "Amount must not be null"); 1088 if (amountToSubtract.compareTo(BigDecimal.ZERO) == 0) { 1089 return this; 1090 } 1091 BigDecimal newAmount = amount.subtract(amountToSubtract); 1092 return BigMoney.of(currency, newAmount); 1093 } 1094 1095 /** 1096 * Returns a copy of this monetary value with the amount subtracted. 1097 * <p> 1098 * This subtracts the specified amount from this monetary amount, returning a new object. 1099 * <p> 1100 * No precision is lost in the result. 1101 * The scale of the result will be the maximum of the two scales. 1102 * For example,'USD 25.95' minus '3.021d' gives 'USD 22.929'. 1103 * <p> 1104 * The amount is converted via {@link BigDecimal#valueOf(double)} which yields 1105 * the most expected answer for most programming scenarios. 1106 * Any {@code double} literal in code will be converted to 1107 * exactly the same BigDecimal with the same scale. 1108 * For example, the literal '1.45d' will be converted to '1.45'. 1109 * <p> 1110 * This instance is immutable and unaffected by this method. 1111 * 1112 * @param amountToSubtract the monetary value to subtract, not null 1113 * @return the new instance with the input amount subtracted, never null 1114 */ 1115 public BigMoney minus(double amountToSubtract) { 1116 if (amountToSubtract == 0) { 1117 return this; 1118 } 1119 BigDecimal newAmount = amount.subtract(BigDecimal.valueOf(amountToSubtract)); 1120 return BigMoney.of(currency, newAmount); 1121 } 1122 1123 /** 1124 * Returns a copy of this monetary value with the amount in major units subtracted. 1125 * <p> 1126 * This subtracts the specified amount in major units from this monetary amount, 1127 * returning a new object. The minor units will be untouched in the result. 1128 * <p> 1129 * No precision is lost in the result. 1130 * The scale of the result will be the maximum of the current scale and 0. 1131 * For example, 'USD 23.45' minus '138' gives 'USD -114.55'. 1132 * <p> 1133 * This instance is immutable and unaffected by this method. 1134 * 1135 * @param amountToSubtract the monetary value to subtract, not null 1136 * @return the new instance with the input amount subtracted, never null 1137 */ 1138 public BigMoney minusMajor(long amountToSubtract) { 1139 if (amountToSubtract == 0) { 1140 return this; 1141 } 1142 BigDecimal newAmount = amount.subtract(BigDecimal.valueOf(amountToSubtract)); 1143 return BigMoney.of(currency, newAmount); 1144 } 1145 1146 /** 1147 * Returns a copy of this monetary value with the amount in minor units subtracted. 1148 * <p> 1149 * This subtracts the specified amount in minor units from this monetary amount, 1150 * returning a new object. 1151 * <p> 1152 * No precision is lost in the result. 1153 * The scale of the result will be the maximum of the current scale and the default currency scale. 1154 * For example, USD 23.45 minus '138' gives 'USD 22.07'. 1155 * <p> 1156 * This instance is immutable and unaffected by this method. 1157 * 1158 * @param amountToSubtract the monetary value to subtract, not null 1159 * @return the new instance with the input amount subtracted, never null 1160 */ 1161 public BigMoney minusMinor(long amountToSubtract) { 1162 if (amountToSubtract == 0) { 1163 return this; 1164 } 1165 BigDecimal newAmount = amount.subtract(BigDecimal.valueOf(amountToSubtract, currency.getDecimalPlaces())); 1166 return BigMoney.of(currency, newAmount); 1167 } 1168 1169 //----------------------------------------------------------------------- 1170 /** 1171 * Returns a copy of this monetary value with the amount in the same currency subtracted 1172 * retaining the scale by rounding the result. 1173 * <p> 1174 * The scale of the result will be the same as the scale of this instance. 1175 * For example,'USD 25.95' minus 'USD 3.029' gives 'USD 22.92 with most rounding modes. 1176 * <p> 1177 * This instance is immutable and unaffected by this method. 1178 * 1179 * @param moneyToSubtract the monetary value to add, not null 1180 * @param roundingMode the rounding mode to use to adjust the scale, not null 1181 * @return the new instance with the input amount subtracted, never null 1182 */ 1183 public BigMoney minusRetainScale(BigMoneyProvider moneyToSubtract, RoundingMode roundingMode) { 1184 BigMoney toSubtract = checkCurrencyEqual(moneyToSubtract); 1185 return minusRetainScale(toSubtract.getAmount(), roundingMode); 1186 } 1187 1188 /** 1189 * Returns a copy of this monetary value with the amount subtracted retaining 1190 * the scale by rounding the result. 1191 * <p> 1192 * The scale of the result will be the same as the scale of this instance. 1193 * For example,'USD 25.95' minus '3.029' gives 'USD 22.92' with most rounding modes. 1194 * <p> 1195 * This instance is immutable and unaffected by this method. 1196 * 1197 * @param amountToSubtract the monetary value to add, not null 1198 * @param roundingMode the rounding mode to use to adjust the scale, not null 1199 * @return the new instance with the input amount subtracted, never null 1200 */ 1201 public BigMoney minusRetainScale(BigDecimal amountToSubtract, RoundingMode roundingMode) { 1202 MoneyUtils.checkNotNull(amountToSubtract, "Amount must not be null"); 1203 if (amountToSubtract.compareTo(BigDecimal.ZERO) == 0) { 1204 return this; 1205 } 1206 BigDecimal newAmount = amount.subtract(amountToSubtract); 1207 newAmount = newAmount.setScale(getScale(), roundingMode); 1208 return BigMoney.of(currency, newAmount); 1209 } 1210 1211 /** 1212 * Returns a copy of this monetary value with the amount subtracted retaining 1213 * the scale by rounding the result. 1214 * <p> 1215 * The scale of the result will be the same as the scale of this instance. 1216 * For example,'USD 25.95' minus '3.029d' gives 'USD 22.92' with most rounding modes. 1217 * <p> 1218 * The amount is converted via {@link BigDecimal#valueOf(double)} which yields 1219 * the most expected answer for most programming scenarios. 1220 * Any {@code double} literal in code will be converted to 1221 * exactly the same BigDecimal with the same scale. 1222 * For example, the literal '1.45d' will be converted to '1.45'. 1223 * <p> 1224 * This instance is immutable and unaffected by this method. 1225 * 1226 * @param amountToSubtract the monetary value to add, not null 1227 * @param roundingMode the rounding mode to use to adjust the scale, not null 1228 * @return the new instance with the input amount subtracted, never null 1229 */ 1230 public BigMoney minusRetainScale(double amountToSubtract, RoundingMode roundingMode) { 1231 if (amountToSubtract == 0) { 1232 return this; 1233 } 1234 BigDecimal newAmount = amount.subtract(BigDecimal.valueOf(amountToSubtract)); 1235 newAmount = newAmount.setScale(getScale(), roundingMode); 1236 return BigMoney.of(currency, newAmount); 1237 } 1238 1239 //----------------------------------------------------------------------- 1240 /** 1241 * Returns a copy of this monetary value multiplied by the specified value. 1242 * <p> 1243 * No precision is lost in the result. 1244 * The result has a scale equal to the sum of the two scales. 1245 * For example, 'USD 1.13' multiplied by '2.5' gives 'USD 2.825'. 1246 * <p> 1247 * This instance is immutable and unaffected by this method. 1248 * 1249 * @param valueToMultiplyBy the scalar value to multiply by, not null 1250 * @return the new multiplied instance, never null 1251 */ 1252 public BigMoney multipliedBy(BigDecimal valueToMultiplyBy) { 1253 MoneyUtils.checkNotNull(valueToMultiplyBy, "Multiplier must not be null"); 1254 if (valueToMultiplyBy.compareTo(BigDecimal.ONE) == 0) { 1255 return this; 1256 } 1257 BigDecimal newAmount = amount.multiply(valueToMultiplyBy); 1258 return BigMoney.of(currency, newAmount); 1259 } 1260 1261 /** 1262 * Returns a copy of this monetary value multiplied by the specified value. 1263 * <p> 1264 * No precision is lost in the result. 1265 * The result has a scale equal to the sum of the two scales. 1266 * For example, 'USD 1.13' multiplied by '2.5' gives 'USD 2.825'. 1267 * <p> 1268 * The amount is converted via {@link BigDecimal#valueOf(double)} which yields 1269 * the most expected answer for most programming scenarios. 1270 * Any {@code double} literal in code will be converted to 1271 * exactly the same BigDecimal with the same scale. 1272 * For example, the literal '1.45d' will be converted to '1.45'. 1273 * <p> 1274 * This instance is immutable and unaffected by this method. 1275 * 1276 * @param valueToMultiplyBy the scalar value to multiply by, not null 1277 * @return the new multiplied instance, never null 1278 */ 1279 public BigMoney multipliedBy(double valueToMultiplyBy) { 1280 if (valueToMultiplyBy == 1) { 1281 return this; 1282 } 1283 BigDecimal newAmount = amount.multiply(BigDecimal.valueOf(valueToMultiplyBy)); 1284 return BigMoney.of(currency, newAmount); 1285 } 1286 1287 /** 1288 * Returns a copy of this monetary value multiplied by the specified value. 1289 * <p> 1290 * No precision is lost in the result. 1291 * The result has a scale equal to the scale of this money. 1292 * For example, 'USD 1.13' multiplied by '2' gives 'USD 2.26'. 1293 * <p> 1294 * This instance is immutable and unaffected by this method. 1295 * 1296 * @param valueToMultiplyBy the scalar value to multiply by, not null 1297 * @return the new multiplied instance, never null 1298 */ 1299 public BigMoney multipliedBy(long valueToMultiplyBy) { 1300 if (valueToMultiplyBy == 1) { 1301 return this; 1302 } 1303 BigDecimal newAmount = amount.multiply(BigDecimal.valueOf(valueToMultiplyBy)); 1304 return BigMoney.of(currency, newAmount); 1305 } 1306 1307 //----------------------------------------------------------------------- 1308 /** 1309 * Returns a copy of this monetary value multiplied by the specified value 1310 * using the specified rounding mode to adjust the scale of the result. 1311 * <p> 1312 * This multiplies this money by the specified value, retaining the scale of this money. 1313 * This will frequently lose precision, hence the need for a rounding mode. 1314 * For example, 'USD 1.13' multiplied by '2.5' and rounding down gives 'USD 2.82'. 1315 * <p> 1316 * This instance is immutable and unaffected by this method. 1317 * 1318 * @param valueToMultiplyBy the scalar value to multiply by, not null 1319 * @param roundingMode the rounding mode to use to bring the decimal places back in line, not null 1320 * @return the new multiplied instance, never null 1321 * @throws ArithmeticException if the rounding fails 1322 */ 1323 public BigMoney multiplyRetainScale(BigDecimal valueToMultiplyBy, RoundingMode roundingMode) { 1324 MoneyUtils.checkNotNull(valueToMultiplyBy, "Multiplier must not be null"); 1325 MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null"); 1326 if (valueToMultiplyBy.compareTo(BigDecimal.ONE) == 0) { 1327 return this; 1328 } 1329 BigDecimal newAmount = amount.multiply(valueToMultiplyBy); 1330 newAmount = newAmount.setScale(getScale(), roundingMode); 1331 return BigMoney.of(currency, newAmount); 1332 } 1333 1334 /** 1335 * Returns a copy of this monetary value multiplied by the specified value 1336 * using the specified rounding mode to adjust the scale of the result. 1337 * <p> 1338 * This multiplies this money by the specified value, retaining the scale of this money. 1339 * This will frequently lose precision, hence the need for a rounding mode. 1340 * For example, 'USD 1.13' multiplied by '2.5' and rounding down gives 'USD 2.82'. 1341 * <p> 1342 * The amount is converted via {@link BigDecimal#valueOf(double)} which yields 1343 * the most expected answer for most programming scenarios. 1344 * Any {@code double} literal in code will be converted to 1345 * exactly the same BigDecimal with the same scale. 1346 * For example, the literal '1.45d' will be converted to '1.45'. 1347 * <p> 1348 * This instance is immutable and unaffected by this method. 1349 * 1350 * @param valueToMultiplyBy the scalar value to multiply by, not null 1351 * @param roundingMode the rounding mode to use to bring the decimal places back in line, not null 1352 * @return the new multiplied instance, never null 1353 * @throws ArithmeticException if the rounding fails 1354 */ 1355 public BigMoney multiplyRetainScale(double valueToMultiplyBy, RoundingMode roundingMode) { 1356 return multiplyRetainScale(BigDecimal.valueOf(valueToMultiplyBy), roundingMode); 1357 } 1358 1359 //----------------------------------------------------------------------- 1360 /** 1361 * Returns a copy of this monetary value divided by the specified value 1362 * using the specified rounding mode to adjust the scale. 1363 * <p> 1364 * The result has the same scale as this instance. 1365 * For example, 'USD 1.13' divided by '2.5' and rounding down gives 'USD 0.45' 1366 * (amount rounded down from 0.452). 1367 * <p> 1368 * This instance is immutable and unaffected by this method. 1369 * 1370 * @param valueToDivideBy the scalar value to divide by, not null 1371 * @param roundingMode the rounding mode to use, not null 1372 * @return the new divided instance, never null 1373 * @throws ArithmeticException if dividing by zero 1374 * @throws ArithmeticException if the rounding fails 1375 */ 1376 public BigMoney dividedBy(BigDecimal valueToDivideBy, RoundingMode roundingMode) { 1377 MoneyUtils.checkNotNull(valueToDivideBy, "Divisor must not be null"); 1378 MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null"); 1379 if (valueToDivideBy.compareTo(BigDecimal.ONE) == 0) { 1380 return this; 1381 } 1382 BigDecimal newAmount = amount.divide(valueToDivideBy, roundingMode); 1383 return BigMoney.of(currency, newAmount); 1384 } 1385 1386 /** 1387 * Returns a copy of this monetary value divided by the specified value 1388 * using the specified rounding mode to adjust the scale. 1389 * <p> 1390 * The result has the same scale as this instance. 1391 * For example, 'USD 1.13' divided by '2.5' and rounding down gives 'USD 0.45' 1392 * (amount rounded down from 0.452). 1393 * <p> 1394 * The amount is converted via {@link BigDecimal#valueOf(double)} which yields 1395 * the most expected answer for most programming scenarios. 1396 * Any {@code double} literal in code will be converted to 1397 * exactly the same BigDecimal with the same scale. 1398 * For example, the literal '1.45d' will be converted to '1.45'. 1399 * <p> 1400 * This instance is immutable and unaffected by this method. 1401 * 1402 * @param valueToDivideBy the scalar value to divide by, not null 1403 * @param roundingMode the rounding mode to use, not null 1404 * @return the new divided instance, never null 1405 * @throws ArithmeticException if dividing by zero 1406 * @throws ArithmeticException if the rounding fails 1407 */ 1408 public BigMoney dividedBy(double valueToDivideBy, RoundingMode roundingMode) { 1409 MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null"); 1410 if (valueToDivideBy == 1) { 1411 return this; 1412 } 1413 BigDecimal newAmount = amount.divide(BigDecimal.valueOf(valueToDivideBy), roundingMode); 1414 return BigMoney.of(currency, newAmount); 1415 } 1416 1417 /** 1418 * Returns a copy of this monetary value divided by the specified value 1419 * using the specified rounding mode to adjust the decimal places in the result. 1420 * <p> 1421 * The result has the same scale as this instance. 1422 * For example, 'USD 1.13' divided by '2' and rounding down gives 'USD 0.56' 1423 * (amount rounded down from 0.565). 1424 * <p> 1425 * This instance is immutable and unaffected by this method. 1426 * 1427 * @param valueToDivideBy the scalar value to divide by, not null 1428 * @param roundingMode the rounding mode to use, not null 1429 * @return the new divided instance, never null 1430 * @throws ArithmeticException if dividing by zero 1431 */ 1432 public BigMoney dividedBy(long valueToDivideBy, RoundingMode roundingMode) { 1433 if (valueToDivideBy == 1) { 1434 return this; 1435 } 1436 BigDecimal newAmount = amount.divide(BigDecimal.valueOf(valueToDivideBy), roundingMode); 1437 return BigMoney.of(currency, newAmount); 1438 } 1439 1440 //----------------------------------------------------------------------- 1441 /** 1442 * Returns a copy of this monetary value with the amount negated. 1443 * <p> 1444 * This instance is immutable and unaffected by this method. 1445 * 1446 * @return the new instance with the amount negated, never null 1447 */ 1448 public BigMoney negated() { 1449 if (isZero()) { 1450 return this; 1451 } 1452 return BigMoney.of(currency, amount.negate()); 1453 } 1454 1455 /** 1456 * Returns a copy of this monetary value with a positive amount. 1457 * <p> 1458 * This instance is immutable and unaffected by this method. 1459 * 1460 * @return the new instance with the amount converted to be positive, never null 1461 */ 1462 public BigMoney abs() { 1463 return (isNegative() ? negated() : this); 1464 } 1465 1466 //----------------------------------------------------------------------- 1467 /** 1468 * Returns a copy of this monetary value rounded to the specified scale without 1469 * changing the current scale. 1470 * <p> 1471 * Scale is described in {@link BigDecimal} and represents the point below which 1472 * the monetary value is zero. Negative scales round increasingly large numbers. 1473 * Unlike {@link #withScale(int)}, this scale of the result is unchanged. 1474 * <ul> 1475 * <li>Rounding 'EUR 45.23' to a scale of -1 returns 40.00 or 50.00 depending on the rounding mode. 1476 * <li>Rounding 'EUR 45.23' to a scale of 0 returns 45.00 or 46.00 depending on the rounding mode. 1477 * <li>Rounding 'EUR 45.23' to a scale of 1 returns 45.20 or 45.30 depending on the rounding mode. 1478 * <li>Rounding 'EUR 45.23' to a scale of 2 has no effect (it already has that scale). 1479 * <li>Rounding 'EUR 45.23' to a scale of 3 has no effect (the scale is not increased). 1480 * </ul> 1481 * This instance is immutable and unaffected by this method. 1482 * 1483 * @param scale the new scale 1484 * @param roundingMode the rounding mode to use, not null 1485 * @return the new instance with the amount converted to be positive, never null 1486 * @throws ArithmeticException if the rounding fails 1487 */ 1488 public BigMoney rounded(int scale, RoundingMode roundingMode) { 1489 MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null"); 1490 if (scale >= getScale()) { 1491 return this; 1492 } 1493 int currentScale = amount.scale(); 1494 BigDecimal newAmount = amount.setScale(scale, roundingMode).setScale(currentScale); 1495 return BigMoney.of(currency, newAmount); 1496 } 1497 1498 //----------------------------------------------------------------------- 1499 /** 1500 * Returns a copy of this monetary value converted into another currency 1501 * using the specified conversion rate. 1502 * <p> 1503 * The scale of the result will be the sum of the scale of this money and 1504 * the scale of the multiplier. If desired, the scale of the result can be 1505 * adjusted to the scale of the new currency using {@link #withCurrencyScale()}. 1506 * <p> 1507 * This instance is immutable and unaffected by this method. 1508 * 1509 * @param currency the new currency, not null 1510 * @param conversionMultipler the conversion factor between the currencies, not null 1511 * @return the new multiplied instance, never null 1512 * @throws IllegalArgumentException if the currency is the same as this currency 1513 * @throws IllegalArgumentException if the conversion multiplier is negative 1514 */ 1515 public BigMoney convertedTo(CurrencyUnit currency, BigDecimal conversionMultipler) { 1516 MoneyUtils.checkNotNull(currency, "CurrencyUnit must not be null"); 1517 MoneyUtils.checkNotNull(conversionMultipler, "Multiplier must not be null"); 1518 if (this.currency == currency) { 1519 throw new IllegalArgumentException("Cannot convert to the same currency"); 1520 } 1521 if (conversionMultipler.compareTo(BigDecimal.ZERO) < 0) { 1522 throw new IllegalArgumentException("Cannot convert using a negative conversion multiplier"); 1523 } 1524 BigDecimal newAmount = amount.multiply(conversionMultipler); 1525 return BigMoney.of(currency, newAmount); 1526 } 1527 1528 /** 1529 * Returns a copy of this monetary value converted into another currency 1530 * using the specified conversion rate, with a rounding mode used to adjust 1531 * the decimal places in the result. 1532 * <p> 1533 * The result will have the same scale as this instance even though it will 1534 * be in a different currency. 1535 * <p> 1536 * This instance is immutable and unaffected by this method. 1537 * 1538 * @param currency the new currency, not null 1539 * @param conversionMultipler the conversion factor between the currencies, not null 1540 * @param roundingMode the rounding mode to use to bring the decimal places back in line, not null 1541 * @return the new multiplied instance, never null 1542 * @throws IllegalArgumentException if the currency is the same as this currency 1543 * @throws IllegalArgumentException if the conversion multiplier is negative 1544 * @throws ArithmeticException if the rounding fails 1545 */ 1546 public BigMoney convertRetainScale(CurrencyUnit currency, BigDecimal conversionMultipler, RoundingMode roundingMode) { 1547 return convertedTo(currency, conversionMultipler).withScale(getScale(), roundingMode); 1548 } 1549 1550 //----------------------------------------------------------------------- 1551 /** 1552 * Implements the {@code BigMoneyProvider} interface, trivially 1553 * returning {@code this}. 1554 * 1555 * @return the money instance, never null 1556 */ 1557 public BigMoney toBigMoney() { 1558 return this; 1559 } 1560 1561 /** 1562 * Converts this money to an instance of {@code Money} without rounding. 1563 * If the scale of this money exceeds the currency scale an exception will be thrown. 1564 * 1565 * @return the money instance, never null 1566 * @throws ArithmeticException if the rounding fails 1567 */ 1568 public Money toMoney() { 1569 return Money.of(this); 1570 } 1571 1572 /** 1573 * Converts this money to an instance of {@code Money}. 1574 * 1575 * @param roundingMode the rounding mode to use, not null 1576 * @return the money instance, never null 1577 * @throws ArithmeticException if the rounding fails 1578 */ 1579 public Money toMoney(RoundingMode roundingMode) { 1580 return Money.of(this, roundingMode); 1581 } 1582 1583 //----------------------------------------------------------------------- 1584 /** 1585 * Checks if this instance and the specified instance have the same currency. 1586 * 1587 * @param money the money to check, not null 1588 * @return true if they have the same currency 1589 */ 1590 public boolean isSameCurrency(BigMoneyProvider money) { 1591 return (currency.equals(of(money).getCurrencyUnit())); 1592 } 1593 1594 //----------------------------------------------------------------------- 1595 /** 1596 * Compares this monetary value to another. 1597 * The compared values must be in the same currency. 1598 * 1599 * @param other the other monetary value, not null 1600 * @return -1 if this is less than , 0 if equal, 1 if greater than 1601 * @throws CurrencyMismatchException if the currencies differ 1602 */ 1603 public int compareTo(BigMoneyProvider other) { 1604 BigMoney otherMoney = of(other); 1605 if (currency.equals(otherMoney.currency) == false) { 1606 throw new CurrencyMismatchException(getCurrencyUnit(), otherMoney.getCurrencyUnit()); 1607 } 1608 return amount.compareTo(otherMoney.amount); 1609 } 1610 1611 /** 1612 * Checks if this monetary value is equal to another. 1613 * <p> 1614 * This ignores the scale of the amount. 1615 * Thus, 'USD 30.00' and 'USD 30' are equal. 1616 * <p> 1617 * The compared values must be in the same currency. 1618 * 1619 * @param other the other monetary value, not null 1620 * @return true is this is greater than the specified monetary value 1621 * @throws CurrencyMismatchException if the currencies differ 1622 * @see #equals(Object) 1623 */ 1624 public boolean isEqual(BigMoneyProvider other) { 1625 return compareTo(other) == 0; 1626 } 1627 1628 /** 1629 * Checks if this monetary value is greater than another. 1630 * The compared values must be in the same currency. 1631 * 1632 * @param other the other monetary value, not null 1633 * @return true is this is greater than the specified monetary value 1634 * @throws CurrencyMismatchException if the currencies differ 1635 */ 1636 public boolean isGreaterThan(BigMoneyProvider other) { 1637 return compareTo(other) > 0; 1638 } 1639 1640 /** 1641 * Checks if this monetary value is less than another. 1642 * The compared values must be in the same currency. 1643 * 1644 * @param other the other monetary value, not null 1645 * @return true is this is less than the specified monetary value 1646 * @throws CurrencyMismatchException if the currencies differ 1647 */ 1648 public boolean isLessThan(BigMoneyProvider other) { 1649 return compareTo(other) < 0; 1650 } 1651 1652 //----------------------------------------------------------------------- 1653 /** 1654 * Checks if this monetary value equals another. 1655 * <p> 1656 * Like BigDecimal, this method compares the scale of the amount. 1657 * Thus, 'USD 30.00' and 'USD 30' are not equal. 1658 * <p> 1659 * The compared values must be in the same currency. 1660 * 1661 * @param other the other object, null returns false 1662 * @return true if this instance equals the other instance 1663 * @see #isEqual 1664 */ 1665 @Override 1666 public boolean equals(Object other) { 1667 if (this == other) { 1668 return true; 1669 } 1670 if (other instanceof BigMoney) { 1671 BigMoney otherMoney = (BigMoney) other; 1672 return currency.equals(otherMoney.getCurrencyUnit()) && 1673 amount.equals(otherMoney.amount); 1674 } 1675 return false; 1676 } 1677 1678 /** 1679 * Returns a hash code for this monetary value. 1680 * 1681 * @return a suitable hash code 1682 */ 1683 @Override 1684 public int hashCode() { 1685 return currency.hashCode() ^ amount.hashCode(); 1686 } 1687 1688 //----------------------------------------------------------------------- 1689 /** 1690 * Gets this monetary value as a string. 1691 * <p> 1692 * The format is the 3 letter ISO currency code, followed by a space, 1693 * followed by the amount as per {@link BigDecimal#toPlainString()}. 1694 * 1695 * @return the string representation of this monetary value, never null 1696 */ 1697 @Override 1698 @ToString 1699 public String toString() { 1700 return new StringBuilder() 1701 .append(currency.getCode()) 1702 .append(' ') 1703 .append(amount.toPlainString()) 1704 .toString(); 1705 } 1706 1707 }