From 104b56d22ec69d1c7d3b418d3d64b0b6acfb5a98 Mon Sep 17 00:00:00 2001 From: Shane Carr Date: Wed, 27 Sep 2017 09:07:45 +0000 Subject: [PATCH] ICU-13177 Finishing documentation in Java and fixing a couple regression test failures. X-SVN-Rev: 40477 --- icu4j/build.xml | 6 + .../icu/impl/number/MultiplierProducer.java | 5 +- .../com/ibm/icu/number/CompactNotation.java | 1 + .../com/ibm/icu/number/CurrencyRounder.java | 2 + .../com/ibm/icu/number/FormattedNumber.java | 82 ++++++++++- .../com/ibm/icu/number/FractionRounder.java | 3 + .../core/src/com/ibm/icu/number/Grouper.java | 22 ++- .../src/com/ibm/icu/number/IntegerWidth.java | 36 ++++- .../icu/number/LocalizedNumberFormatter.java | 78 ++++++++--- .../core/src/com/ibm/icu/number/Notation.java | 6 + .../com/ibm/icu/number/NumberFormatter.java | 74 +++++++++- .../icu/number/NumberFormatterSettings.java | 130 ++++++++++++++---- .../ibm/icu/number/NumberPropertyMapper.java | 24 +++- .../core/src/com/ibm/icu/number/Rounder.java | 14 ++ .../ibm/icu/number/ScientificNotation.java | 3 + .../com/ibm/icu/number/SimpleNotation.java | 11 ++ .../number/UnlocalizedNumberFormatter.java | 36 ++++- .../core/src/com/ibm/icu/number/package.html | 23 ++++ .../src/com/ibm/icu/text/DecimalFormat.java | 6 +- .../src/com/ibm/icu/text/NumberingSystem.java | 6 + .../test/format/NumberRegressionTests.java | 7 +- .../dev/test/number/DecimalQuantityTest.java | 2 +- ...rTest.java => NumberFormatterApiTest.java} | 2 +- 23 files changed, 511 insertions(+), 68 deletions(-) create mode 100644 icu4j/main/classes/core/src/com/ibm/icu/number/package.html rename icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/{NumberFormatterTest.java => NumberFormatterApiTest.java} (99%) diff --git a/icu4j/build.xml b/icu4j/build.xml index 9e7f6c51282..61126ff509a 100644 --- a/icu4j/build.xml +++ b/icu4j/build.xml @@ -1239,6 +1239,7 @@ + @@ -1273,6 +1274,7 @@ + @@ -1318,6 +1320,7 @@ + @@ -1522,6 +1525,7 @@ + @@ -1543,6 +1547,7 @@ + @@ -1588,6 +1593,7 @@ + diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/MultiplierProducer.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/MultiplierProducer.java index 2e7b96def7f..ea422465a01 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/MultiplierProducer.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/MultiplierProducer.java @@ -2,6 +2,9 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.impl.number; +/** + * An interface used by compact notation and scientific notation to choose a multiplier while rounding. + */ public interface MultiplierProducer { int getMultiplier(int magnitude); -} \ No newline at end of file +} diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java b/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java index bc5375eb483..da412a366ca 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java @@ -30,6 +30,7 @@ import com.ibm.icu.util.ULocale; * {@link Notation}. * * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public class CompactNotation extends Notation { diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/CurrencyRounder.java b/icu4j/main/classes/core/src/com/ibm/icu/number/CurrencyRounder.java index 041494fa45f..97e36314a0c 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/CurrencyRounder.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/CurrencyRounder.java @@ -12,6 +12,7 @@ import com.ibm.icu.util.Currency; * To create a CurrencyRounder, use one of the factory methods on Rounder. * * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public abstract class CurrencyRounder extends Rounder { @@ -35,6 +36,7 @@ public abstract class CurrencyRounder extends Rounder { * The currency to associate with this rounding strategy. * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public Rounder withCurrency(Currency currency) { diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java b/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java index 69762031366..293adc09dca 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java @@ -14,6 +14,14 @@ import com.ibm.icu.impl.number.NumberStringBuilder; import com.ibm.icu.text.PluralRules.IFixedDecimal; import com.ibm.icu.util.ICUUncheckedIOException; +/** + * The result of a number formatting operation. This class allows the result to be exported in several data types, + * including a String, an AttributedCharacterIterator, and a BigDecimal. + * + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see NumberFormatter + */ public class FormattedNumber { NumberStringBuilder nsb; DecimalQuantity fq; @@ -25,11 +33,35 @@ public class FormattedNumber { this.micros = micros; } + /** + * Creates a String representation of the the formatted number. + * + * @return a String containing the localized number. + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see NumberFormatter + */ @Override public String toString() { return nsb.toString(); } + /** + * Append the formatted number to an Appendable, such as a StringBuilder. This may be slightly more efficient than + * creating a String. + * + *

+ * If an IOException occurs when appending to the Appendable, an unchecked {@link ICUUncheckedIOException} is thrown + * instead. + * + * @param appendable + * The Appendable to which to append the formatted number string. + * @return The same Appendable, for chaining. + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see Appendable + * @see NumberFormatter + */ public A appendTo(A appendable) { try { appendable.append(nsb); @@ -40,6 +72,25 @@ public class FormattedNumber { return appendable; } + /** + * Determine the start and end indices of the first occurrence of the given field in the output string. + * This allows you to determine the locations of the integer part, fraction part, and sign. + * + *

+ * If multiple different field attributes are needed, this method can be called repeatedly, or if all field + * attributes are needed, consider using getFieldIterator(). + * + *

+ * If a field occurs multiple times in an output string, such as a grouping separator, this method will only ever + * return the first occurrence. Use getFieldIterator() to access all occurrences of an attribute. + * + * @param fieldPosition + * The FieldPosition to populate with the start and end indices of the desired field. + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see com.ibm.icu.text.NumberFormat.Field + * @see NumberFormatter + */ public void populateFieldPosition(FieldPosition fieldPosition) { populateFieldPosition(fieldPosition, 0); } @@ -54,17 +105,40 @@ public class FormattedNumber { fq.populateUFieldPosition(fieldPosition); } - public AttributedCharacterIterator getAttributes() { + /** + * Export the formatted number as an AttributedCharacterIterator. This allows you to determine which characters in + * the output string correspond to which fields, such as the integer part, fraction part, and sign. + * + *

+ * If information on only one field is needed, consider using populateFieldPosition() instead. + * + * @return An AttributedCharacterIterator, containing information on the field attributes of the number string. + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see com.ibm.icu.text.NumberFormat.Field + * @see AttributedCharacterIterator + * @see NumberFormatter + */ + public AttributedCharacterIterator getFieldIterator() { return nsb.getIterator(); } + /** + * Export the formatted number as a BigDecimal. This endpoint is useful for obtaining the exact number being printed + * after scaling and rounding have been applied by the number formatting pipeline. + * + * @return A BigDecimal representation of the formatted number. + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see NumberFormatter + */ public BigDecimal toBigDecimal() { return fq.toBigDecimal(); } /** * @internal - * @deprecated This API a technology preview. It is not stable and may change or go away in an upcoming release. + * @deprecated This API is ICU internal only. */ @Deprecated public String getPrefix() { @@ -79,7 +153,7 @@ public class FormattedNumber { /** * @internal - * @deprecated This API a technology preview. It is not stable and may change or go away in an upcoming release. + * @deprecated This API is ICU internal only. */ @Deprecated public String getSuffix() { @@ -94,7 +168,7 @@ public class FormattedNumber { /** * @internal - * @deprecated This API a technology preview. It is not stable and may change or go away in an upcoming release. + * @deprecated This API is ICU internal only. */ @Deprecated public IFixedDecimal getFixedDecimal() { diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/FractionRounder.java b/icu4j/main/classes/core/src/com/ibm/icu/number/FractionRounder.java index a8ff7fc3a4f..5662e360b82 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/FractionRounder.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/FractionRounder.java @@ -12,6 +12,7 @@ import com.ibm.icu.impl.number.RoundingUtils; * To create a FractionRounder, use one of the factory methods on Rounder. * * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public abstract class FractionRounder extends Rounder { @@ -34,6 +35,7 @@ public abstract class FractionRounder extends Rounder { * The number of significant figures to guarantee. * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public Rounder withMinDigits(int minSignificantDigits) { @@ -61,6 +63,7 @@ public abstract class FractionRounder extends Rounder { * Round the number to no more than this number of significant figures. * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public Rounder withMaxDigits(int maxSignificantDigits) { diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/Grouper.java b/icu4j/main/classes/core/src/com/ibm/icu/number/Grouper.java index e5b030be036..6d1c1935c4c 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/Grouper.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/Grouper.java @@ -5,6 +5,11 @@ package com.ibm.icu.number; import com.ibm.icu.impl.number.DecimalQuantity; import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo; +/** + * @internal + * @deprecated This API is a technical preview. It is likely to change in an upcoming release. + */ +@Deprecated public class Grouper { // Conveniences for Java handling of bytes @@ -27,14 +32,29 @@ public class Grouper { this.min2 = min2; } + /** + * @internal + * @deprecated This API is a technical preview. It is likely to change in an upcoming release. + */ + @Deprecated public static Grouper defaults() { return DEFAULTS; } + /** + * @internal + * @deprecated This API is a technical preview. It is likely to change in an upcoming release. + */ + @Deprecated public static Grouper minTwoDigits() { return MIN2; } + /** + * @internal + * @deprecated This API is a technical preview. It is likely to change in an upcoming release. + */ + @Deprecated public static Grouper none() { return NONE; } @@ -91,4 +111,4 @@ public class Grouper { return position >= 0 && (position % grouping2) == 0 && value.getUpperDisplayMagnitude() - grouping1 + 1 >= (min2 ? 2 : 1); } - } \ No newline at end of file +} \ No newline at end of file diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/IntegerWidth.java b/icu4j/main/classes/core/src/com/ibm/icu/number/IntegerWidth.java index e1fcb9c87ee..90fe0dcc391 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/IntegerWidth.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/IntegerWidth.java @@ -4,7 +4,16 @@ package com.ibm.icu.number; import com.ibm.icu.impl.number.RoundingUtils; -@SuppressWarnings("unused") +/** + * A class that defines the strategy for padding and truncating integers before the decimal separator. + * + *

+ * To create an IntegerWidth, use one of the factory methods. + * + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see NumberFormatter + */ public class IntegerWidth { /* package-private */ static final IntegerWidth DEFAULT = new IntegerWidth(1, -1); @@ -17,6 +26,19 @@ public class IntegerWidth { this.maxInt = maxInt; } + /** + * Pad numbers at the beginning with zeros to guarantee a certain number of numerals before the decimal separator. + * + *

+ * For example, with minInt=3, the number 55 will get printed as "055". + * + * @param minInt + * The minimum number of places before the decimal separator. + * @return An IntegerWidth for chaining or passing to the NumberFormatter integerWidth() setter. + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see NumberFormatter + */ public static IntegerWidth zeroFillTo(int minInt) { if (minInt == 1) { return DEFAULT; @@ -28,6 +50,18 @@ public class IntegerWidth { } } + /** + * Truncate numbers exceeding a certain number of numerals before the decimal separator. + * + * For example, with maxInt=3, the number 1234 will get printed as "234". + * + * @param maxInt + * The maximum number of places before the decimal separator. + * @return An IntegerWidth for passing to the NumberFormatter integerWidth() setter. + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see NumberFormatter + */ public IntegerWidth truncateAt(int maxInt) { if (maxInt == this.maxInt) { return this; diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java b/icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java index d17ec7e2554..4ff6d406456 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java @@ -2,6 +2,7 @@ // License & terms of use: http://www.unicode.org/copyright.html#License package com.ibm.icu.number; +import java.math.BigInteger; import java.util.Objects; import java.util.concurrent.atomic.AtomicLongFieldUpdater; @@ -10,9 +11,19 @@ import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD; import com.ibm.icu.impl.number.MacroProps; import com.ibm.icu.impl.number.MicroProps; import com.ibm.icu.impl.number.NumberStringBuilder; +import com.ibm.icu.math.BigDecimal; +import com.ibm.icu.util.CurrencyAmount; import com.ibm.icu.util.Measure; import com.ibm.icu.util.MeasureUnit; +/** + * A NumberFormatter that has a locale associated with it; this means .format() methods are available. + * + * @see NumberFormatter + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see NumberFormatter + */ public class LocalizedNumberFormatter extends NumberFormatterSettings { static final AtomicLongFieldUpdater callCount = AtomicLongFieldUpdater @@ -26,18 +37,66 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings + * The unit specified here overrides any unit that may have been specified in the setter chain. This method is + * intended for cases when each input to the number formatter has a different unit. + * + * @param input + * The number to format. + * @return A FormattedNumber object; call .toString() to get the string. + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + * @see NumberFormatter + */ public FormattedNumber format(Measure input) { MeasureUnit unit = input.getUnit(); Number number = input.getNumber(); @@ -90,24 +149,7 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings parent, int key, Object value) { - super(parent, key, value); - } - } } \ No newline at end of file diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/Notation.java b/icu4j/main/classes/core/src/com/ibm/icu/number/Notation.java index d0fafcc2e98..c1ec6c98859 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/Notation.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/Notation.java @@ -9,6 +9,7 @@ import com.ibm.icu.text.CompactDecimalFormat.CompactStyle; * A class that defines the notation style to be used when formatting numbers in NumberFormatter. * * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public class Notation { @@ -46,6 +47,7 @@ public class Notation { * * @return A ScientificNotation for chaining or passing to the NumberFormatter notation() setter. * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public static ScientificNotation scientific() { @@ -73,6 +75,7 @@ public class Notation { * * @return A ScientificNotation for chaining or passing to the NumberFormatter notation() setter. * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public static ScientificNotation engineering() { @@ -119,6 +122,7 @@ public class Notation { * * @return A CompactNotation for passing to the NumberFormatter notation() setter. * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public static CompactNotation compactShort() { @@ -146,6 +150,7 @@ public class Notation { * * @return A CompactNotation for passing to the NumberFormatter notation() setter. * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public static CompactNotation compactLong() { @@ -175,6 +180,7 @@ public class Notation { * * @return A SimpleNotation for passing to the NumberFormatter notation() setter. * @draft ICU 60 + * @provisional This API might change or be removed in a future release. * @see NumberFormatter */ public static SimpleNotation simple() { diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java index c0c3faa0d23..0530acac21b 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java @@ -9,6 +9,56 @@ import com.ibm.icu.impl.number.MacroProps; import com.ibm.icu.text.DecimalFormatSymbols; import com.ibm.icu.util.ULocale; +/** + * The main entrypoint to the localized number formatting library introduced in ICU 60. Basic usage examples: + * + *

+ * // Most basic usage:
+ * NumberFormatter.withLocale(...).format(123).toString();  // 1,234 in en-US
+ *
+ * // Custom notation, unit, and rounding strategy:
+ * NumberFormatter.with()
+ *     .notation(Notation.compactShort())
+ *     .unit(Currency.getInstance("EUR"))
+ *     .rounding(Rounder.maxDigits(2))
+ *     .locale(...)
+ *     .format(1234)
+ *     .toString();  // €1.2K in en-US
+ *
+ * // Create a formatter in a private static final field:
+ * private static final LocalizedNumberFormatter formatter = NumberFormatter.withLocale(...)
+ *     .unit(NoUnit.PERCENT)
+ *     .rounding(Rounder.fixedFraction(3));
+ * formatter.format(5.9831).toString();  // 5.983% in en-US
+ *
+ * // Create a "template" in a private static final field but without setting a locale until the call site:
+ * private static final UnlocalizedNumberFormatter template = NumberFormatter.with()
+ *     .sign(SignDisplay.ALWAYS)
+ *     .unitWidth(UnitWidth.FULL_NAME);
+ * template.locale(...).format(new Measure(1234, MeasureUnit.METER)).toString();  // +1,234 meters in en-US
+ * 
+ * + *

+ * This API offers more features than {@link com.ibm.icu.text.DecimalFormat} and is geared toward new users of ICU. + * + *

+ * NumberFormatter instances are immutable and thread safe. This means that invoking a configuration method has no + * effect on the receiving instance; you must store and use the new number formatter instance it returns instead. + * + *

+ * UnlocalizedNumberFormatter formatter = UnlocalizedNumberFormatter.with().notation(Notation.scientific());
+ * formatter.rounding(Rounder.maxFraction(2)); // does nothing!
+ * formatter.locale(ULocale.ENGLISH).format(9.8765).toString(); // prints "9.8765E0", not "9.88E0"
+ * 
+ * + *

+ * This API is based on the fluent design pattern popularized by libraries such as Google's Guava. For + * extensive details on the design of this API, read the design doc. + * + * @author Shane Carr + * @draft ICU 60 + * @provisional This API might change or be removed in a future release. + */ public final class NumberFormatter { private static final UnlocalizedNumberFormatter BASE = new UnlocalizedNumberFormatter(); @@ -17,7 +67,6 @@ public final class NumberFormatter { * An enum declaring how to render units, including currencies. Example outputs when formatting 123 USD and 123 * meters in en-CA: * - *

*