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 }