0001: /*
0002: *
0003: * @(#)NumberFormat.java 1.55 06/10/10
0004: *
0005: * Portions Copyright 2000-2006 Sun Microsystems, Inc. All Rights
0006: * Reserved. Use is subject to license terms.
0007: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0008: *
0009: * This program is free software; you can redistribute it and/or
0010: * modify it under the terms of the GNU General Public License version
0011: * 2 only, as published by the Free Software Foundation.
0012: *
0013: * This program is distributed in the hope that it will be useful, but
0014: * WITHOUT ANY WARRANTY; without even the implied warranty of
0015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0016: * General Public License version 2 for more details (a copy is
0017: * included at /legal/license.txt).
0018: *
0019: * You should have received a copy of the GNU General Public License
0020: * version 2 along with this work; if not, write to the Free Software
0021: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0022: * 02110-1301 USA
0023: *
0024: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0025: * Clara, CA 95054 or visit www.sun.com if you need additional
0026: * information or have any questions.
0027: */
0028:
0029: /*
0030: * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
0031: * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
0032: *
0033: * The original version of this source code and documentation is copyrighted
0034: * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
0035: * materials are provided under terms of a License Agreement between Taligent
0036: * and Sun. This technology is protected by multiple US and International
0037: * patents. This notice and attribution to Taligent may not be removed.
0038: * Taligent is a registered trademark of Taligent, Inc.
0039: *
0040: */
0041:
0042: package java.text;
0043:
0044: import java.io.InvalidObjectException;
0045: import java.io.IOException;
0046: import java.io.ObjectInputStream;
0047: import java.io.ObjectOutputStream;
0048: import java.math.BigInteger;
0049: import java.util.Currency;
0050: import java.util.HashMap;
0051: import java.util.Hashtable;
0052: import java.util.Locale;
0053: import java.util.Map;
0054: import java.util.ResourceBundle;
0055: import sun.text.resources.LocaleData;
0056:
0057: /**
0058: * <code>NumberFormat</code> is the abstract base class for all number
0059: * formats. This class provides the interface for formatting and parsing
0060: * numbers. <code>NumberFormat</code> also provides methods for determining
0061: * which locales have number formats, and what their names are.
0062: *
0063: * <p>
0064: * <code>NumberFormat</code> helps you to format and parse numbers for any locale.
0065: * Your code can be completely independent of the locale conventions for
0066: * decimal points, thousands-separators, or even the particular decimal
0067: * digits used, or whether the number format is even decimal.
0068: *
0069: * <p>
0070: * To format a number for the current Locale, use one of the factory
0071: * class methods:
0072: * <blockquote>
0073: * <pre>
0074: * myString = NumberFormat.getInstance().format(myNumber);
0075: * </pre>
0076: * </blockquote>
0077: * If you are formatting multiple numbers, it is
0078: * more efficient to get the format and use it multiple times so that
0079: * the system doesn't have to fetch the information about the local
0080: * language and country conventions multiple times.
0081: * <blockquote>
0082: * <pre>
0083: * NumberFormat nf = NumberFormat.getInstance();
0084: * for (int i = 0; i < a.length; ++i) {
0085: * output.println(nf.format(myNumber[i]) + "; ");
0086: * }
0087: * </pre>
0088: * </blockquote>
0089: * To format a number for a different Locale, specify it in the
0090: * call to <code>getInstance</code>.
0091: * <blockquote>
0092: * <pre>
0093: * NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
0094: * </pre>
0095: * </blockquote>
0096: * You can also use a <code>NumberFormat</code> to parse numbers:
0097: * <blockquote>
0098: * <pre>
0099: * myNumber = nf.parse(myString);
0100: * </pre>
0101: * </blockquote>
0102: * Use <code>getInstance</code> or <code>getNumberInstance</code> to get the
0103: * normal number format. Use <code>getIntegerInstance</code> to get an
0104: * integer number format. Use <code>getCurrencyInstance</code> to get the
0105: * currency number format. And use <code>getPercentInstance</code> to get a
0106: * format for displaying percentages. With this format, a fraction like
0107: * 0.53 is displayed as 53%.
0108: *
0109: * <p>
0110: * You can also control the display of numbers with such methods as
0111: * <code>setMinimumFractionDigits</code>.
0112: * If you want even more control over the format or parsing,
0113: * or want to give your users more control,
0114: * you can try casting the <code>NumberFormat</code> you get from the factory methods
0115: * to a <code>DecimalFormat</code>. This will work for the vast majority
0116: * of locales; just remember to put it in a <code>try</code> block in case you
0117: * encounter an unusual one.
0118: *
0119: * <p>
0120: * NumberFormat and DecimalFormat are designed such that some controls
0121: * work for formatting and others work for parsing. The following is
0122: * the detailed description for each these control methods,
0123: * <p>
0124: * setParseIntegerOnly : only affects parsing, e.g.
0125: * if true, "3456.78" -> 3456 (and leaves the parse position just after index 6)
0126: * if false, "3456.78" -> 3456.78 (and leaves the parse position just after index 8)
0127: * This is independent of formatting. If you want to not show a decimal point
0128: * where there might be no digits after the decimal point, use
0129: * setDecimalSeparatorAlwaysShown.
0130: * <p>
0131: * setDecimalSeparatorAlwaysShown : only affects formatting, and only where
0132: * there might be no digits after the decimal point, such as with a pattern
0133: * like "#,##0.##", e.g.,
0134: * if true, 3456.00 -> "3,456."
0135: * if false, 3456.00 -> "3456"
0136: * This is independent of parsing. If you want parsing to stop at the decimal
0137: * point, use setParseIntegerOnly.
0138: *
0139: * <p>
0140: * You can also use forms of the <code>parse</code> and <code>format</code>
0141: * methods with <code>ParsePosition</code> and <code>FieldPosition</code> to
0142: * allow you to:
0143: * <ul>
0144: * <li> progressively parse through pieces of a string
0145: * <li> align the decimal point and other areas
0146: * </ul>
0147: * For example, you can align numbers in two ways:
0148: * <ol>
0149: * <li> If you are using a monospaced font with spacing for alignment,
0150: * you can pass the <code>FieldPosition</code> in your format call, with
0151: * <code>field</code> = <code>INTEGER_FIELD</code>. On output,
0152: * <code>getEndIndex</code> will be set to the offset between the
0153: * last character of the integer and the decimal. Add
0154: * (desiredSpaceCount - getEndIndex) spaces at the front of the string.
0155: *
0156: * <li> If you are using proportional fonts,
0157: * instead of padding with spaces, measure the width
0158: * of the string in pixels from the start to <code>getEndIndex</code>.
0159: * Then move the pen by
0160: * (desiredPixelWidth - widthToAlignmentPoint) before drawing the text.
0161: * It also works where there is no decimal, but possibly additional
0162: * characters at the end, e.g., with parentheses in negative
0163: * numbers: "(12)" for -12.
0164: * </ol>
0165: *
0166: * <h4><a name="synchronization">Synchronization</a></h4>
0167: *
0168: * <p>
0169: * Number formats are generally not synchronized.
0170: * It is recommended to create separate format instances for each thread.
0171: * If multiple threads access a format concurrently, it must be synchronized
0172: * externally.
0173: *
0174: * @see DecimalFormat
0175: * @see ChoiceFormat
0176: * @version 1.47, 01/19/00
0177: * @author Mark Davis
0178: * @author Helena Shih
0179: */
0180: public abstract class NumberFormat extends Format {
0181:
0182: /**
0183: * Field constant used to construct a FieldPosition object. Signifies that
0184: * the position of the integer part of a formatted number should be returned.
0185: * @see java.text.FieldPosition
0186: */
0187: public static final int INTEGER_FIELD = 0;
0188:
0189: /**
0190: * Field constant used to construct a FieldPosition object. Signifies that
0191: * the position of the fraction part of a formatted number should be returned.
0192: * @see java.text.FieldPosition
0193: */
0194: public static final int FRACTION_FIELD = 1;
0195:
0196: /**
0197: * Formats an object to produce a string.
0198: * This general routines allows polymorphic parsing and
0199: * formatting for objects.
0200: * @param number the object to format
0201: * @param toAppendTo where the text is to be appended
0202: * @param pos On input: an alignment field, if desired.
0203: * On output: the offsets of the alignment field.
0204: * @return the value passed in as toAppendTo (this allows chaining,
0205: * as with StringBuffer.append())
0206: * @exception IllegalArgumentException when the Format cannot format the
0207: * given object.
0208: * @see java.text.FieldPosition
0209: */
0210: public final StringBuffer format(Object number,
0211: StringBuffer toAppendTo, FieldPosition pos) {
0212: if (number instanceof Long
0213: || (number instanceof BigInteger && ((BigInteger) number)
0214: .bitLength() < 64)) {
0215: return format(((Number) number).longValue(), toAppendTo,
0216: pos);
0217: }
0218: /* Here is the code that's required to get all the bits we can out of
0219: * BigDecimal into a long or double. In the interests of simplicity, we
0220: * don't use this code; we just convert BigDecimal values into doubles.
0221: * (Actually, to really do things right, you'd compare against both
0222: * Long.MIN_VALUE and Long.MAX_VALUE, since they differ in magnitude.)
0223: * NOTE: <B>java.math.BigDecimal</B> is found in J2ME CDC profiles such as
0224: * J2ME Foundation Profile.
0225: * Liu 6/98
0226: */
0227: // else if (number instanceof BigDecimal) {
0228: // BigDecimal bd = (BigDecimal)number;
0229: // try {
0230: // if (bd.setScale(0, BigDecimal.ROUND_UNNECESSARY).
0231: // abs().compareTo(new BigDecimal("9223372036854775807")) <= 0) {
0232: // return format(((Number)number).longValue(), toAppendTo, pos);
0233: // }
0234: // }
0235: // catch (ArithmeticException e) {}
0236: // return format(((Number)number).doubleValue(), toAppendTo, pos);
0237: // }
0238: else if (number instanceof Number) {
0239: return format(((Number) number).doubleValue(), toAppendTo,
0240: pos);
0241: } else {
0242: throw new IllegalArgumentException(
0243: "Cannot format given Object as a Number");
0244: }
0245: }
0246:
0247: /**
0248: * Parses text from a string to produce a <code>Number</code>.
0249: * <p>
0250: * The method attempts to parse text starting at the index given by
0251: * <code>pos</code>.
0252: * If parsing succeeds, then the index of <code>pos</code> is updated
0253: * to the index after the last character used (parsing does not necessarily
0254: * use all characters up to the end of the string), and the parsed
0255: * number is returned. The updated <code>pos</code> can be used to
0256: * indicate the starting point for the next call to this method.
0257: * If an error occurs, then the index of <code>pos</code> is not
0258: * changed, the error index of <code>pos</code> is set to the index of
0259: * the character where the error occurred, and null is returned.
0260: * <p>
0261: * See the {@link #parse(String, ParsePosition)} method for more information
0262: * on number parsing.
0263: *
0264: * @param source A <code>String</code>, part of which should be parsed.
0265: * @param pos A <code>ParsePosition</code> object with index and error
0266: * index information as described above.
0267: * @return A <code>Number</code> parsed from the string. In case of
0268: * error, returns null.
0269: * @exception NullPointerException if <code>pos</code> is null.
0270: */
0271: public final Object parseObject(String source, ParsePosition pos) {
0272: return parse(source, pos);
0273: }
0274:
0275: /**
0276: * Specialization of format.
0277: * @see java.text.Format#format
0278: */
0279: public final String format(double number) {
0280: return format(number, new StringBuffer(),
0281: DontCareFieldPosition.INSTANCE).toString();
0282: }
0283:
0284: /**
0285: * Specialization of format.
0286: * @see java.text.Format#format
0287: */
0288: public final String format(long number) {
0289: return format(number, new StringBuffer(),
0290: DontCareFieldPosition.INSTANCE).toString();
0291: }
0292:
0293: /**
0294: * Specialization of format.
0295: * @see java.text.Format#format
0296: */
0297: public abstract StringBuffer format(double number,
0298: StringBuffer toAppendTo, FieldPosition pos);
0299:
0300: /**
0301: * Specialization of format.
0302: * @see java.text.Format#format
0303: */
0304: public abstract StringBuffer format(long number,
0305: StringBuffer toAppendTo, FieldPosition pos);
0306:
0307: /**
0308: * Returns a Long if possible (e.g., within the range [Long.MIN_VALUE,
0309: * Long.MAX_VALUE] and with no decimals), otherwise a Double.
0310: * If IntegerOnly is set, will stop at a decimal
0311: * point (or equivalent; e.g., for rational numbers "1 2/3", will stop
0312: * after the 1).
0313: * Does not throw an exception; if no object can be parsed, index is
0314: * unchanged!
0315: * @see java.text.NumberFormat#isParseIntegerOnly
0316: * @see java.text.Format#parseObject
0317: */
0318: public abstract Number parse(String source,
0319: ParsePosition parsePosition);
0320:
0321: /**
0322: * Parses text from the beginning of the given string to produce a number.
0323: * The method may not use the entire text of the given string.
0324: * <p>
0325: * See the {@link #parse(String, ParsePosition)} method for more information
0326: * on number parsing.
0327: *
0328: * @param source A <code>String</code> whose beginning should be parsed.
0329: * @return A <code>Number</code> parsed from the string.
0330: * @exception ParseException if the beginning of the specified string
0331: * cannot be parsed.
0332: */
0333: public Number parse(String source) throws ParseException {
0334: ParsePosition parsePosition = new ParsePosition(0);
0335: Number result = parse(source, parsePosition);
0336: if (parsePosition.index == 0) {
0337: throw new ParseException("Unparseable number: \"" + source
0338: + "\"", parsePosition.errorIndex);
0339: }
0340: return result;
0341: }
0342:
0343: /**
0344: * Returns true if this format will parse numbers as integers only.
0345: * For example in the English locale, with ParseIntegerOnly true, the
0346: * string "1234." would be parsed as the integer value 1234 and parsing
0347: * would stop at the "." character. Of course, the exact format accepted
0348: * by the parse operation is locale dependant and determined by sub-classes
0349: * of NumberFormat.
0350: */
0351: public boolean isParseIntegerOnly() {
0352: return parseIntegerOnly;
0353: }
0354:
0355: /**
0356: * Sets whether or not numbers should be parsed as integers only.
0357: * @see #isParseIntegerOnly
0358: */
0359: public void setParseIntegerOnly(boolean value) {
0360: parseIntegerOnly = value;
0361: }
0362:
0363: //============== Locale Stuff =====================
0364:
0365: /**
0366: * Returns the default number format for the current default locale.
0367: * The default format is one of the styles provided by the other
0368: * factory methods: getNumberInstance, getIntegerInstance,
0369: * getCurrencyInstance or getPercentInstance.
0370: * Exactly which one is locale dependant.
0371: */
0372: public final static NumberFormat getInstance() {
0373: return getInstance(Locale.getDefault(), NUMBERSTYLE);
0374: }
0375:
0376: /**
0377: * Returns the default number format for the specified locale.
0378: * The default format is one of the styles provided by the other
0379: * factory methods: getNumberInstance, getIntegerInstance,
0380: * getCurrencyInstance or getPercentInstance.
0381: * Exactly which one is locale dependant.
0382: */
0383: public static NumberFormat getInstance(Locale inLocale) {
0384: return getInstance(inLocale, NUMBERSTYLE);
0385: }
0386:
0387: /**
0388: * Returns a general-purpose number format for the current default locale.
0389: */
0390: public final static NumberFormat getNumberInstance() {
0391: return getInstance(Locale.getDefault(), NUMBERSTYLE);
0392: }
0393:
0394: /**
0395: * Returns a general-purpose number format for the specified locale.
0396: */
0397: public static NumberFormat getNumberInstance(Locale inLocale) {
0398: return getInstance(inLocale, NUMBERSTYLE);
0399: }
0400:
0401: /**
0402: * Returns an integer number format for the current default locale. The
0403: * returned number format is configured to round floating point numbers
0404: * to the nearest integer using IEEE half-even rounding (see {@link
0405: * java.math.BigDecimal#ROUND_HALF_EVEN ROUND_HALF_EVEN}) for formatting,
0406: * and to parse only the integer part of an input string (see {@link
0407: * #isParseIntegerOnly isParseIntegerOnly}).
0408: * NOTE: <B>java.math.BigDecimal</B> is found in J2ME CDC profiles such as
0409: * J2ME Foundation Profile.
0410: * @return a number format for integer values
0411: * @since 1.4
0412: */
0413: public final static NumberFormat getIntegerInstance() {
0414: return getInstance(Locale.getDefault(), INTEGERSTYLE);
0415: }
0416:
0417: /**
0418: * Returns an integer number format for the specified locale. The
0419: * returned number format is configured to round floating point numbers
0420: * to the nearest integer using IEEE half-even rounding (see {@link
0421: * java.math.BigDecimal#ROUND_HALF_EVEN ROUND_HALF_EVEN}) for formatting,
0422: * and to parse only the integer part of an input string (see {@link
0423: * #isParseIntegerOnly isParseIntegerOnly}).
0424: * NOTE: <B>java.math.BigDecimal</B> is found in J2ME CDC profiles such as
0425: * J2ME Foundation Profile.
0426: *
0427: * @param inLocale the locale for which a number format is needed
0428: * @return a number format for integer values
0429: * @since 1.4
0430: */
0431: public static NumberFormat getIntegerInstance(Locale inLocale) {
0432: return getInstance(inLocale, INTEGERSTYLE);
0433: }
0434:
0435: /**
0436: * Returns a currency format for the current default locale.
0437: */
0438: public final static NumberFormat getCurrencyInstance() {
0439: return getInstance(Locale.getDefault(), CURRENCYSTYLE);
0440: }
0441:
0442: /**
0443: * Returns a currency format for the specified locale.
0444: */
0445: public static NumberFormat getCurrencyInstance(Locale inLocale) {
0446: return getInstance(inLocale, CURRENCYSTYLE);
0447: }
0448:
0449: /**
0450: * Returns a percentage format for the current default locale.
0451: */
0452: public final static NumberFormat getPercentInstance() {
0453: return getInstance(Locale.getDefault(), PERCENTSTYLE);
0454: }
0455:
0456: /**
0457: * Returns a percentage format for the specified locale.
0458: */
0459: public static NumberFormat getPercentInstance(Locale inLocale) {
0460: return getInstance(inLocale, PERCENTSTYLE);
0461: }
0462:
0463: /**
0464: * Returns a scientific format for the current default locale.
0465: */
0466: /*public*/final static NumberFormat getScientificInstance() {
0467: return getInstance(Locale.getDefault(), SCIENTIFICSTYLE);
0468: }
0469:
0470: /**
0471: * Returns a scientific format for the specified locale.
0472: */
0473: /*public*/static NumberFormat getScientificInstance(Locale inLocale) {
0474: return getInstance(inLocale, SCIENTIFICSTYLE);
0475: }
0476:
0477: /**
0478: * Get the set of Locales for which NumberFormats are installed
0479: * @return available locales
0480: */
0481: public static Locale[] getAvailableLocales() {
0482: return LocaleData.getAvailableLocales("NumberPatterns");
0483: }
0484:
0485: /**
0486: * Overrides hashCode
0487: */
0488: public int hashCode() {
0489: return maximumIntegerDigits * 37 + maxFractionDigits;
0490: // just enough fields for a reasonable distribution
0491: }
0492:
0493: /**
0494: * Overrides equals
0495: */
0496: public boolean equals(Object obj) {
0497: if (obj == null)
0498: return false;
0499: if (this == obj)
0500: return true;
0501: if (getClass() != obj.getClass())
0502: return false;
0503: NumberFormat other = (NumberFormat) obj;
0504: return (maximumIntegerDigits == other.maximumIntegerDigits
0505: && minimumIntegerDigits == other.minimumIntegerDigits
0506: && maximumFractionDigits == other.maximumFractionDigits
0507: && minimumFractionDigits == other.minimumFractionDigits
0508: && groupingUsed == other.groupingUsed && parseIntegerOnly == other.parseIntegerOnly);
0509: }
0510:
0511: /**
0512: * Overrides Cloneable
0513: */
0514: public Object clone() {
0515: NumberFormat other = (NumberFormat) super .clone();
0516: return other;
0517: }
0518:
0519: /**
0520: * Returns true if grouping is used in this format. For example, in the
0521: * English locale, with grouping on, the number 1234567 might be formatted
0522: * as "1,234,567". The grouping separator as well as the size of each group
0523: * is locale dependant and is determined by sub-classes of NumberFormat.
0524: * @see #setGroupingUsed
0525: */
0526: public boolean isGroupingUsed() {
0527: return groupingUsed;
0528: }
0529:
0530: /**
0531: * Set whether or not grouping will be used in this format.
0532: * @see #isGroupingUsed
0533: */
0534: public void setGroupingUsed(boolean newValue) {
0535: groupingUsed = newValue;
0536: }
0537:
0538: /**
0539: * Returns the maximum number of digits allowed in the integer portion of a
0540: * number.
0541: * @see #setMaximumIntegerDigits
0542: */
0543: public int getMaximumIntegerDigits() {
0544: return maximumIntegerDigits;
0545: }
0546:
0547: /**
0548: * Sets the maximum number of digits allowed in the integer portion of a
0549: * number. maximumIntegerDigits must be >= minimumIntegerDigits. If the
0550: * new value for maximumIntegerDigits is less than the current value
0551: * of minimumIntegerDigits, then minimumIntegerDigits will also be set to
0552: * the new value.
0553: * @param newValue the maximum number of integer digits to be shown; if
0554: * less than zero, then zero is used. The concrete subclass may enforce an
0555: * upper limit to this value appropriate to the numeric type being formatted.
0556: * @see #getMaximumIntegerDigits
0557: */
0558: public void setMaximumIntegerDigits(int newValue) {
0559: maximumIntegerDigits = Math.max(0, newValue);
0560: if (minimumIntegerDigits > maximumIntegerDigits)
0561: minimumIntegerDigits = maximumIntegerDigits;
0562: }
0563:
0564: /**
0565: * Returns the minimum number of digits allowed in the integer portion of a
0566: * number.
0567: * @see #setMinimumIntegerDigits
0568: */
0569: public int getMinimumIntegerDigits() {
0570: return minimumIntegerDigits;
0571: }
0572:
0573: /**
0574: * Sets the minimum number of digits allowed in the integer portion of a
0575: * number. minimumIntegerDigits must be <= maximumIntegerDigits. If the
0576: * new value for minimumIntegerDigits exceeds the current value
0577: * of maximumIntegerDigits, then maximumIntegerDigits will also be set to
0578: * the new value
0579: * @param newValue the minimum number of integer digits to be shown; if
0580: * less than zero, then zero is used. The concrete subclass may enforce an
0581: * upper limit to this value appropriate to the numeric type being formatted.
0582: * @see #getMinimumIntegerDigits
0583: */
0584: public void setMinimumIntegerDigits(int newValue) {
0585: minimumIntegerDigits = Math.max(0, newValue);
0586: if (minimumIntegerDigits > maximumIntegerDigits)
0587: maximumIntegerDigits = minimumIntegerDigits;
0588: }
0589:
0590: /**
0591: * Returns the maximum number of digits allowed in the fraction portion of a
0592: * number.
0593: * @see #setMaximumFractionDigits
0594: */
0595: public int getMaximumFractionDigits() {
0596: return maximumFractionDigits;
0597: }
0598:
0599: /**
0600: * Sets the maximum number of digits allowed in the fraction portion of a
0601: * number. maximumFractionDigits must be >= minimumFractionDigits. If the
0602: * new value for maximumFractionDigits is less than the current value
0603: * of minimumFractionDigits, then minimumFractionDigits will also be set to
0604: * the new value.
0605: * @param newValue the maximum number of fraction digits to be shown; if
0606: * less than zero, then zero is used. The concrete subclass may enforce an
0607: * upper limit to this value appropriate to the numeric type being formatted.
0608: * @see #getMaximumFractionDigits
0609: */
0610: public void setMaximumFractionDigits(int newValue) {
0611: maximumFractionDigits = Math.max(0, newValue);
0612: if (maximumFractionDigits < minimumFractionDigits)
0613: minimumFractionDigits = maximumFractionDigits;
0614: }
0615:
0616: /**
0617: * Returns the minimum number of digits allowed in the fraction portion of a
0618: * number.
0619: * @see #setMinimumFractionDigits
0620: */
0621: public int getMinimumFractionDigits() {
0622: return minimumFractionDigits;
0623: }
0624:
0625: /**
0626: * Sets the minimum number of digits allowed in the fraction portion of a
0627: * number. minimumFractionDigits must be <= maximumFractionDigits. If the
0628: * new value for minimumFractionDigits exceeds the current value
0629: * of maximumFractionDigits, then maximumIntegerDigits will also be set to
0630: * the new value
0631: * @param newValue the minimum number of fraction digits to be shown; if
0632: * less than zero, then zero is used. The concrete subclass may enforce an
0633: * upper limit to this value appropriate to the numeric type being formatted.
0634: * @see #getMinimumFractionDigits
0635: */
0636: public void setMinimumFractionDigits(int newValue) {
0637: minimumFractionDigits = Math.max(0, newValue);
0638: if (maximumFractionDigits < minimumFractionDigits)
0639: maximumFractionDigits = minimumFractionDigits;
0640: }
0641:
0642: /**
0643: * Gets the currency used by this number format when formatting
0644: * currency values. The initial value is derived in a locale dependent
0645: * way. The returned value may be null if no valid
0646: * currency could be determined and no currency has been set using
0647: * {@link #setCurrency(java.util.Currency) setCurrency}.
0648: * <p>
0649: * The default implementation throws
0650: * <code>UnsupportedOperationException</code>.
0651: *
0652: * @return the currency used by this number format, or <code>null</code>
0653: * @exception UnsupportedOperationException if the number format class
0654: * doesn't implement currency formatting
0655: * @since 1.4
0656: */
0657: public Currency getCurrency() {
0658: throw new UnsupportedOperationException();
0659: }
0660:
0661: /**
0662: * Sets the currency used by this number format when formatting
0663: * currency values. This does not update the minimum or maximum
0664: * number of fraction digits used by the number format.
0665: * <p>
0666: * The default implementation throws
0667: * <code>UnsupportedOperationException</code>.
0668: *
0669: * @param currency the new currency to be used by this number format
0670: * @exception UnsupportedOperationException if the number format class
0671: * doesn't implement currency formatting
0672: * @exception NullPointerException if <code>currency</code> is null
0673: * @since 1.4
0674: */
0675: public void setCurrency(Currency currency) {
0676: throw new UnsupportedOperationException();
0677: }
0678:
0679: // =======================privates===============================
0680:
0681: private static NumberFormat getInstance(Locale desiredLocale,
0682: int choice) {
0683: /* try the cache first */
0684: String[] numberPatterns = (String[]) cachedLocaleData
0685: .get(desiredLocale);
0686: if (numberPatterns == null) { /* cache miss */
0687: ResourceBundle resource = LocaleData
0688: .getLocaleElements(desiredLocale);
0689: numberPatterns = resource.getStringArray("NumberPatterns");
0690: /* update cache */
0691: cachedLocaleData.put(desiredLocale, numberPatterns);
0692: }
0693:
0694: DecimalFormatSymbols symbols = new DecimalFormatSymbols(
0695: desiredLocale);
0696: int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
0697: DecimalFormat format = new DecimalFormat(numberPatterns[entry],
0698: symbols);
0699:
0700: if (choice == INTEGERSTYLE) {
0701: format.setMaximumFractionDigits(0);
0702: format.setDecimalSeparatorAlwaysShown(false);
0703: format.setParseIntegerOnly(true);
0704: } else if (choice == CURRENCYSTYLE) {
0705: format.adjustForCurrencyDefaultFractionDigits();
0706: }
0707:
0708: return format;
0709: }
0710:
0711: /**
0712: * First, read in the default serializable data.
0713: *
0714: * Then, if <code>serialVersionOnStream</code> is less than 1, indicating that
0715: * the stream was written by JDK 1.1,
0716: * set the <code>int</code> fields such as <code>maximumIntegerDigits</code>
0717: * to be equal to the <code>byte</code> fields such as <code>maxIntegerDigits</code>,
0718: * since the <code>int</code> fields were not present in JDK 1.1.
0719: * Finally, set serialVersionOnStream back to the maximum allowed value so that
0720: * default serialization will work properly if this object is streamed out again.
0721: *
0722: * <p>If <code>minimumIntegerDigits</code> is greater than
0723: * <code>maximumIntegerDigits</code> or <code>minimumFractionDigits</code>
0724: * is greater than <code>maximumFractionDigits</code>, then the stream data
0725: * is invalid and this method throws an <code>InvalidObjectException</code>.
0726: * In addition, if any of these values is negative, then this method throws
0727: * an <code>InvalidObjectException</code>.
0728: *
0729: * @since 1.2
0730: */
0731: private void readObject(ObjectInputStream stream)
0732: throws IOException, ClassNotFoundException {
0733: stream.defaultReadObject();
0734: if (serialVersionOnStream < 1) {
0735: // Didn't have additional int fields, reassign to use them.
0736: maximumIntegerDigits = maxIntegerDigits;
0737: minimumIntegerDigits = minIntegerDigits;
0738: maximumFractionDigits = maxFractionDigits;
0739: minimumFractionDigits = minFractionDigits;
0740: }
0741: if (minimumIntegerDigits > maximumIntegerDigits
0742: || minimumFractionDigits > maximumFractionDigits
0743: || minimumIntegerDigits < 0
0744: || minimumFractionDigits < 0) {
0745: throw new InvalidObjectException(
0746: "Digit count range invalid");
0747: }
0748: serialVersionOnStream = currentSerialVersion;
0749: }
0750:
0751: /**
0752: * Write out the default serializable data, after first setting
0753: * the <code>byte</code> fields such as <code>maxIntegerDigits</code> to be
0754: * equal to the <code>int</code> fields such as <code>maximumIntegerDigits</code>
0755: * (or to <code>Byte.MAX_VALUE</code>, whichever is smaller), for compatibility
0756: * with the JDK 1.1 version of the stream format.
0757: *
0758: * @since 1.2
0759: */
0760: private void writeObject(ObjectOutputStream stream)
0761: throws IOException {
0762: maxIntegerDigits = (maximumIntegerDigits > Byte.MAX_VALUE) ? Byte.MAX_VALUE
0763: : (byte) maximumIntegerDigits;
0764: minIntegerDigits = (minimumIntegerDigits > Byte.MAX_VALUE) ? Byte.MAX_VALUE
0765: : (byte) minimumIntegerDigits;
0766: maxFractionDigits = (maximumFractionDigits > Byte.MAX_VALUE) ? Byte.MAX_VALUE
0767: : (byte) maximumFractionDigits;
0768: minFractionDigits = (minimumFractionDigits > Byte.MAX_VALUE) ? Byte.MAX_VALUE
0769: : (byte) minimumFractionDigits;
0770: stream.defaultWriteObject();
0771: }
0772:
0773: /**
0774: * Cache to hold the NumberPatterns of a Locale.
0775: */
0776: private static final Hashtable cachedLocaleData = new Hashtable(3);
0777:
0778: // Constants used by factory methods to specify a style of format.
0779: private static final int NUMBERSTYLE = 0;
0780: private static final int CURRENCYSTYLE = 1;
0781: private static final int PERCENTSTYLE = 2;
0782: private static final int SCIENTIFICSTYLE = 3;
0783: private static final int INTEGERSTYLE = 4;
0784:
0785: /**
0786: * True if the the grouping (i.e. thousands) separator is used when
0787: * formatting and parsing numbers.
0788: *
0789: * @serial
0790: * @see #isGroupingUsed
0791: */
0792: private boolean groupingUsed = true;
0793:
0794: /**
0795: * The maximum number of digits allowed in the integer portion of a
0796: * number. <code>maxIntegerDigits</code> must be greater than or equal to
0797: * <code>minIntegerDigits</code>.
0798: * <p>
0799: * <strong>Note:</strong> This field exists only for serialization
0800: * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
0801: * <code>int</code> field <code>maximumIntegerDigits</code> is used instead.
0802: * When writing to a stream, <code>maxIntegerDigits</code> is set to
0803: * <code>maximumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
0804: * whichever is smaller. When reading from a stream, this field is used
0805: * only if <code>serialVersionOnStream</code> is less than 1.
0806: *
0807: * @serial
0808: * @see #getMaximumIntegerDigits
0809: */
0810: private byte maxIntegerDigits = 40;
0811:
0812: /**
0813: * The minimum number of digits allowed in the integer portion of a
0814: * number. <code>minimumIntegerDigits</code> must be less than or equal to
0815: * <code>maximumIntegerDigits</code>.
0816: * <p>
0817: * <strong>Note:</strong> This field exists only for serialization
0818: * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
0819: * <code>int</code> field <code>minimumIntegerDigits</code> is used instead.
0820: * When writing to a stream, <code>minIntegerDigits</code> is set to
0821: * <code>minimumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
0822: * whichever is smaller. When reading from a stream, this field is used
0823: * only if <code>serialVersionOnStream</code> is less than 1.
0824: *
0825: * @serial
0826: * @see #getMinimumIntegerDigits
0827: */
0828: private byte minIntegerDigits = 1;
0829:
0830: /**
0831: * The maximum number of digits allowed in the fractional portion of a
0832: * number. <code>maximumFractionDigits</code> must be greater than or equal to
0833: * <code>minimumFractionDigits</code>.
0834: * <p>
0835: * <strong>Note:</strong> This field exists only for serialization
0836: * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
0837: * <code>int</code> field <code>maximumFractionDigits</code> is used instead.
0838: * When writing to a stream, <code>maxFractionDigits</code> is set to
0839: * <code>maximumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
0840: * whichever is smaller. When reading from a stream, this field is used
0841: * only if <code>serialVersionOnStream</code> is less than 1.
0842: *
0843: * @serial
0844: * @see #getMaximumFractionDigits
0845: */
0846: private byte maxFractionDigits = 3; // invariant, >= minFractionDigits
0847:
0848: /**
0849: * The minimum number of digits allowed in the fractional portion of a
0850: * number. <code>minimumFractionDigits</code> must be less than or equal to
0851: * <code>maximumFractionDigits</code>.
0852: * <p>
0853: * <strong>Note:</strong> This field exists only for serialization
0854: * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
0855: * <code>int</code> field <code>minimumFractionDigits</code> is used instead.
0856: * When writing to a stream, <code>minFractionDigits</code> is set to
0857: * <code>minimumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
0858: * whichever is smaller. When reading from a stream, this field is used
0859: * only if <code>serialVersionOnStream</code> is less than 1.
0860: *
0861: * @serial
0862: * @see #getMinimumFractionDigits
0863: */
0864: private byte minFractionDigits = 0;
0865:
0866: /**
0867: * True if this format will parse numbers as integers only.
0868: *
0869: * @serial
0870: * @see #isParseIntegerOnly
0871: */
0872: private boolean parseIntegerOnly = false;
0873:
0874: // new fields for 1.2. byte is too small for integer digits.
0875:
0876: /**
0877: * The maximum number of digits allowed in the integer portion of a
0878: * number. <code>maximumIntegerDigits</code> must be greater than or equal to
0879: * <code>minimumIntegerDigits</code>.
0880: *
0881: * @serial
0882: * @since 1.2
0883: * @see #getMaximumIntegerDigits
0884: */
0885: private int maximumIntegerDigits = 40;
0886:
0887: /**
0888: * The minimum number of digits allowed in the integer portion of a
0889: * number. <code>minimumIntegerDigits</code> must be less than or equal to
0890: * <code>maximumIntegerDigits</code>.
0891: *
0892: * @serial
0893: * @since 1.2
0894: * @see #getMinimumIntegerDigits
0895: */
0896: private int minimumIntegerDigits = 1;
0897:
0898: /**
0899: * The maximum number of digits allowed in the fractional portion of a
0900: * number. <code>maximumFractionDigits</code> must be greater than or equal to
0901: * <code>minimumFractionDigits</code>.
0902: *
0903: * @serial
0904: * @since 1.2
0905: * @see #getMaximumFractionDigits
0906: */
0907: private int maximumFractionDigits = 3; // invariant, >= minFractionDigits
0908:
0909: /**
0910: * The minimum number of digits allowed in the fractional portion of a
0911: * number. <code>minimumFractionDigits</code> must be less than or equal to
0912: * <code>maximumFractionDigits</code>.
0913: *
0914: * @serial
0915: * @since 1.2
0916: * @see #getMinimumFractionDigits
0917: */
0918: private int minimumFractionDigits = 0;
0919:
0920: static final int currentSerialVersion = 1;
0921:
0922: /**
0923: * Describes the version of <code>NumberFormat</code> present on the stream.
0924: * Possible values are:
0925: * <ul>
0926: * <li><b>0</b> (or uninitialized): the JDK 1.1 version of the stream format.
0927: * In this version, the <code>int</code> fields such as
0928: * <code>maximumIntegerDigits</code> were not present, and the <code>byte</code>
0929: * fields such as <code>maxIntegerDigits</code> are used instead.
0930: *
0931: * <li><b>1</b>: the 1.2 version of the stream format. The values of the
0932: * <code>byte</code> fields such as <code>maxIntegerDigits</code> are ignored,
0933: * and the <code>int</code> fields such as <code>maximumIntegerDigits</code>
0934: * are used instead.
0935: * </ul>
0936: * When streaming out a <code>NumberFormat</code>, the most recent format
0937: * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
0938: * is always written.
0939: *
0940: * @serial
0941: * @since 1.2
0942: */
0943: private int serialVersionOnStream = currentSerialVersion;
0944:
0945: // Removed "implements Cloneable" clause. Needs to update serialization
0946: // ID for backward compatibility.
0947: static final long serialVersionUID = -2308460125733713944L;
0948:
0949: //
0950: // class for AttributedCharacterIterator attributes
0951: //
0952: /**
0953: * Defines constants that are used as attribute keys in the
0954: * <code>AttributedCharacterIterator</code> returned
0955: * from <code>NumberFormat.formatToCharacterIterator</code> and as
0956: * field identifiers in <code>FieldPosition</code>.
0957: *
0958: * @since 1.4
0959: */
0960: public static class Field extends Format.Field {
0961: // table of all instances in this class, used by readResolve
0962: private static final Map instanceMap = new HashMap(11);
0963:
0964: /**
0965: * Creates a Field instance with the specified
0966: * name.
0967: *
0968: * @param name Name of the attribute
0969: */
0970: protected Field(String name) {
0971: super (name);
0972: if (this .getClass() == NumberFormat.Field.class) {
0973: instanceMap.put(name, this );
0974: }
0975: }
0976:
0977: /**
0978: * Resolves instances being deserialized to the predefined constants.
0979: *
0980: * @throws InvalidObjectException if the constant could not be
0981: * resolved.
0982: * @return resolved NumberFormat.Field constant
0983: */
0984: protected Object readResolve() throws InvalidObjectException {
0985: if (this .getClass() != NumberFormat.Field.class) {
0986: throw new InvalidObjectException(
0987: "subclass didn't correctly implement readResolve");
0988: }
0989:
0990: Object instance = instanceMap.get(getName());
0991: if (instance != null) {
0992: return instance;
0993: } else {
0994: throw new InvalidObjectException(
0995: "unknown attribute name");
0996: }
0997: }
0998:
0999: /**
1000: * Constant identifying the integer field.
1001: */
1002: public static final Field INTEGER = new Field("integer");
1003:
1004: /**
1005: * Constant identifying the fraction field.
1006: */
1007: public static final Field FRACTION = new Field("fraction");
1008:
1009: /**
1010: * Constant identifying the exponent field.
1011: */
1012: public static final Field EXPONENT = new Field("exponent");
1013:
1014: /**
1015: * Constant identifying the decimal separator field.
1016: */
1017: public static final Field DECIMAL_SEPARATOR = new Field(
1018: "decimal separator");
1019:
1020: /**
1021: * Constant identifying the sign field.
1022: */
1023: public static final Field SIGN = new Field("sign");
1024:
1025: /**
1026: * Constant identifying the grouping separator field.
1027: */
1028: public static final Field GROUPING_SEPARATOR = new Field(
1029: "grouping separator");
1030:
1031: /**
1032: * Constant identifying the exponent symbol field.
1033: */
1034: public static final Field EXPONENT_SYMBOL = new Field(
1035: "exponent symbol");
1036:
1037: /**
1038: * Constant identifying the percent field.
1039: */
1040: public static final Field PERCENT = new Field("percent");
1041:
1042: /**
1043: * Constant identifying the permille field.
1044: */
1045: public static final Field PERMILLE = new Field("per mille");
1046:
1047: /**
1048: * Constant identifying the currency field.
1049: */
1050: public static final Field CURRENCY = new Field("currency");
1051:
1052: /**
1053: * Constant identifying the exponent sign field.
1054: */
1055: public static final Field EXPONENT_SIGN = new Field(
1056: "exponent sign");
1057: }
1058: }
|