< prev index next >

src/java.base/share/classes/java/text/DecimalFormat.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -46,13 +46,10 @@
 import java.math.RoundingMode;
 import java.text.spi.NumberFormatProvider;
 import java.util.ArrayList;
 import java.util.Currency;
 import java.util.Locale;
-import java.util.ResourceBundle;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import sun.util.locale.provider.LocaleProviderAdapter;
 import sun.util.locale.provider.ResourceBundleBasedAdapter;
 

@@ -155,11 +152,11 @@
  * 1,0000,0000.  If you supply a pattern with multiple grouping characters, the
  * interval between the last one and the end of the integer is the one that is
  * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
  * <code>"##,####,####"</code>.
  *
- * <h4>Special Pattern Characters</h4>
+ * <h4><a id="special_pattern_character">Special Pattern Characters</a></h4>
  *
  * <p>Many characters in a pattern are taken literally; they are matched during
  * parsing and output unchanged during formatting.  Special characters, on the
  * other hand, stand for other characters, strings, or classes of characters.
  * They must be quoted, unless noted otherwise, if they are to appear in the

@@ -570,18 +567,15 @@
      * @param delegate notified of locations of sub fields
      * @exception       ArithmeticException if rounding is needed with rounding
      *                  mode being set to RoundingMode.UNNECESSARY
      * @return The formatted number string
      */
-    private StringBuffer format(double number, StringBuffer result,
+    StringBuffer format(double number, StringBuffer result,
                                 FieldDelegate delegate) {
-        if (Double.isNaN(number) ||
-           (Double.isInfinite(number) && multiplier == 0)) {
-            int iFieldStart = result.length();
-            result.append(symbols.getNaN());
-            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
-                               iFieldStart, result.length(), result);
+
+        boolean nanOrInfinity = handleNaN(number, result, delegate);
+        if (nanOrInfinity) {
             return result;
         }
 
         /* Detecting whether a double is negative is easy with the exception of
          * the value -0.0.  This is a double which has a zero mantissa (and

@@ -597,10 +591,60 @@
 
         if (multiplier != 1) {
             number *= multiplier;
         }
 
+        nanOrInfinity = handleInfinity(number, result, delegate, isNegative);
+        if (nanOrInfinity) {
+            return result;
+        }
+
+        if (isNegative) {
+            number = -number;
+        }
+
+        // at this point we are guaranteed a nonnegative finite number.
+        assert (number >= 0 && !Double.isInfinite(number));
+        return doubleSubformat(number, result, delegate, isNegative);
+    }
+
+    /**
+     * Checks if the given {@code number} is {@code Double.NaN}. if yes;
+     * appends the NaN symbol to the result string. The NaN string is
+     * determined by the DecimalFormatSymbols object.
+     * @param number the double number to format
+     * @param result where the text is to be appended
+     * @param delegate notified of locations of sub fields
+     * @return true, if number is a NaN; false otherwise
+     */
+    boolean handleNaN(double number, StringBuffer result,
+            FieldDelegate delegate) {
+        if (Double.isNaN(number)
+                || (Double.isInfinite(number) && multiplier == 0)) {
+            int iFieldStart = result.length();
+            result.append(symbols.getNaN());
+            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
+                    iFieldStart, result.length(), result);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Checks if the given {@code number} is {@code Double.NEGATIVE_INFINITY}
+     * or {@code Double.POSITIVE_INFINITY}. if yes;
+     * appends the infinity string to the result string. The infinity string is
+     * determined by the DecimalFormatSymbols object.
+     * @param number the double number to format
+     * @param result where the text is to be appended
+     * @param delegate notified of locations of sub fields
+     * @param isNegative whether the given {@code number} is negative
+     * @return true, if number is a {@code Double.NEGATIVE_INFINITY} or
+     *         {@code Double.POSITIVE_INFINITY}; false otherwise
+     */
+    boolean handleInfinity(double number, StringBuffer result,
+            FieldDelegate delegate, boolean isNegative) {
         if (Double.isInfinite(number)) {
             if (isNegative) {
                 append(result, negativePrefix, delegate,
                        getNegativePrefixFieldPositions(), Field.SIGN);
             } else {

@@ -619,28 +663,25 @@
             } else {
                 append(result, positiveSuffix, delegate,
                        getPositiveSuffixFieldPositions(), Field.SIGN);
             }
 
-            return result;
+            return true;
         }
-
-        if (isNegative) {
-            number = -number;
+        return false;
         }
 
-        // at this point we are guaranteed a nonnegative finite number.
-        assert(number >= 0 && !Double.isInfinite(number));
-
-        synchronized(digitList) {
+    StringBuffer doubleSubformat(double number, StringBuffer result,
+            FieldDelegate delegate, boolean isNegative) {
+        synchronized (digitList) {
             int maxIntDigits = super.getMaximumIntegerDigits();
             int minIntDigits = super.getMinimumIntegerDigits();
             int maxFraDigits = super.getMaximumFractionDigits();
             int minFraDigits = super.getMinimumFractionDigits();
 
-            digitList.set(isNegative, number, useExponentialNotation ?
-                          maxIntDigits + maxFraDigits : maxFraDigits,
+            digitList.set(isNegative, number, useExponentialNotation
+                    ? maxIntDigits + maxFraDigits : maxFraDigits,
                           !useExponentialNotation);
             return subformat(result, delegate, isNegative, false,
                        maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
         }
     }

@@ -681,11 +722,11 @@
      * @return The formatted number string
      * @exception        ArithmeticException if rounding is needed with rounding
      *                   mode being set to RoundingMode.UNNECESSARY
      * @see java.text.FieldPosition
      */
-    private StringBuffer format(long number, StringBuffer result,
+    StringBuffer format(long number, StringBuffer result,
                                FieldDelegate delegate) {
         boolean isNegative = (number < 0);
         if (isNegative) {
             number = -number;
         }

@@ -772,11 +813,11 @@
      * @param delegate notified of locations of sub fields
      * @exception        ArithmeticException if rounding is needed with rounding
      *                   mode being set to RoundingMode.UNNECESSARY
      * @return The formatted number string
      */
-    private StringBuffer format(BigDecimal number, StringBuffer result,
+    StringBuffer format(BigDecimal number, StringBuffer result,
                                 FieldDelegate delegate) {
         if (multiplier != 1) {
             number = number.multiply(getBigDecimalMultiplier());
         }
         boolean isNegative = number.signum() == -1;

@@ -833,11 +874,11 @@
      * @return The formatted number string
      * @exception        ArithmeticException if rounding is needed with rounding
      *                   mode being set to RoundingMode.UNNECESSARY
      * @see java.text.FieldPosition
      */
-    private StringBuffer format(BigInteger number, StringBuffer result,
+    StringBuffer format(BigInteger number, StringBuffer result,
                                FieldDelegate delegate, boolean formatLong) {
         if (multiplier != 1) {
             number = number.multiply(getBigIntegerMultiplier());
         }
         boolean isNegative = number.signum() == -1;

@@ -915,11 +956,11 @@
                 "Cannot format given Object as a Number");
         }
         return delegate.getIterator(sb.toString());
     }
 
-    // ==== Begin fast-path formating logic for double =========================
+    // ==== Begin fast-path formatting logic for double =========================
 
     /* Fast-path formatting will be used for format(double ...) methods iff a
      * number of conditions are met (see checkAndSetFastPathStatus()):
      * - Only if instance properties meet the right predefined conditions.
      * - The abs value of the double to format is <= Integer.MAX_VALUE.

@@ -1660,37 +1701,87 @@
                           fastPathData.firstUsedIndex,
                           fastPathData.lastFreeIndex - fastPathData.firstUsedIndex);
 
     }
 
+    /**
+     * Sets the {@code DigitList} used by this {@code DecimalFormat}
+     * instance.
+     * @param number the number to format
+     * @param isNegative true, if the number is negative; false otherwise
+     * @param maxDigits the max digits
+     */
+    void setDigitList(Number number, boolean isNegative, int maxDigits) {
+
+        if (number instanceof Double) {
+            digitList.set(isNegative, (Double) number, maxDigits, true);
+        } else if (number instanceof BigDecimal) {
+            digitList.set(isNegative, (BigDecimal) number, maxDigits, true);
+        } else if (number instanceof Long) {
+            digitList.set(isNegative, (Long) number, maxDigits);
+        } else if (number instanceof BigInteger) {
+            digitList.set(isNegative, (BigInteger) number, maxDigits);
+        }
+    }
+
     // ======== End fast-path formating logic for double =========================
 
     /**
      * Complete the formatting of a finite number.  On entry, the digitList must
      * be filled in with the correct digits.
      */
     private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
                                    boolean isNegative, boolean isInteger,
                                    int maxIntDigits, int minIntDigits,
                                    int maxFraDigits, int minFraDigits) {
-        // NOTE: This isn't required anymore because DigitList takes care of this.
-        //
-        //  // The negative of the exponent represents the number of leading
-        //  // zeros between the decimal and the first non-zero digit, for
-        //  // a value < 0.1 (e.g., for 0.00123, -fExponent == 2).  If this
-        //  // is more than the maximum fraction digits, then we have an underflow
-        //  // for the printed representation.  We recognize this here and set
-        //  // the DigitList representation to zero in this situation.
-        //
-        //  if (-digitList.decimalAt >= getMaximumFractionDigits())
-        //  {
-        //      digitList.count = 0;
-        //  }
 
+        // process prefix
+        if (isNegative) {
+            append(result, negativePrefix, delegate,
+                    getNegativePrefixFieldPositions(), Field.SIGN);
+        } else {
+            append(result, positivePrefix, delegate,
+                    getPositivePrefixFieldPositions(), Field.SIGN);
+        }
+
+        // process number
+        subformatNumber(result, delegate, isNegative, isInteger,
+                maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
+
+        // process suffix
+        if (isNegative) {
+            append(result, negativeSuffix, delegate,
+                    getNegativeSuffixFieldPositions(), Field.SIGN);
+        } else {
+            append(result, positiveSuffix, delegate,
+                    getPositiveSuffixFieldPositions(), Field.SIGN);
+        }
+
+        return result;
+    }
+
+    /**
+     * Subformats number part using the {@code DigitList} of this
+     * {@code DecimalFormat} instance.
+     * @param result where the text is to be appended
+     * @param delegate notified of the location of sub fields
+     * @param isNegative true, if the number is negative; false otherwise
+     * @param isInteger true, if the number is an integer; false otherwise
+     * @param maxIntDigits maximum integer digits
+     * @param minIntDigits minimum integer digits
+     * @param maxFraDigits maximum fraction digits
+     * @param minFraDigits minimum fraction digits
+     */
+    void subformatNumber(StringBuffer result, FieldDelegate delegate,
+            boolean isNegative, boolean isInteger,
+            int maxIntDigits, int minIntDigits,
+            int maxFraDigits, int minFraDigits) {
+
+        char grouping = symbols.getGroupingSeparator();
         char zero = symbols.getZeroDigit();
         int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
-        char grouping = symbols.getGroupingSeparator();
+
         char decimal = isCurrencyFormat ?
             symbols.getMonetaryDecimalSeparator() :
             symbols.getDecimalSeparator();
 
         /* Per bug 4147706, DecimalFormat must respect the sign of numbers which

@@ -1701,27 +1792,18 @@
          */
         if (digitList.isZero()) {
             digitList.decimalAt = 0; // Normalize
         }
 
-        if (isNegative) {
-            append(result, negativePrefix, delegate,
-                   getNegativePrefixFieldPositions(), Field.SIGN);
-        } else {
-            append(result, positivePrefix, delegate,
-                   getPositivePrefixFieldPositions(), Field.SIGN);
-        }
-
         if (useExponentialNotation) {
             int iFieldStart = result.length();
             int iFieldEnd = -1;
             int fFieldStart = -1;
 
             // Minimum integer digits are handled in exponential format by
             // adjusting the exponent.  For example, 0.01234 with 3 minimum
             // integer digits is "123.4E-4".
-
             // Maximum integer digits are interpreted as indicating the
             // repeating range.  This is useful for engineering notation, in
             // which the exponent is restricted to a multiple of 3.  For
             // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
             // If maximum integer digits are > 1 and are larger than

@@ -1957,20 +2039,10 @@
 
             // Record field information for caller.
             delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
                                fFieldStart, result.length(), result);
         }
-
-        if (isNegative) {
-            append(result, negativeSuffix, delegate,
-                   getNegativeSuffixFieldPositions(), Field.SIGN);
-        } else {
-            append(result, positiveSuffix, delegate,
-                   getPositiveSuffixFieldPositions(), Field.SIGN);
-        }
-
-        return result;
     }
 
     /**
      * Appends the String <code>string</code> to <code>result</code>.
      * <code>delegate</code> is notified of all  the
< prev index next >