Number Formats

To print a formatted number in Java, perform these two steps:

  1. Format the number as a string.

  2. Print the string.

Simple, right? Of course, this is a little like the old recipe for rabbit stew:

  1. Catch a rabbit.

  2. Boil rabbit in pot with vegetables and spices.

Obviously, step 1 is the tricky part. Fortunately, formatting numbers as strings is somewhat easier than catching a rabbit. The key class that formats numbers as strings is java.text.NumberFormat. This is an abstract subclass of java.text.Format.

public abstract class NumberFormat extends Format implements Cloneable

Concrete subclasses such as java.text.DecimalFormat implement formatting policies for particular kinds of numbers. The static NumberFormat.getAvailableLocales( ) method returns a list of all installed locales that provide number formats. (There may be a few locales that only provide date or text formats, not number formats.)

public static Locale[] getAvailableLocales( )

You can request a NumberFormat object for the default locale of the host computer or for a locale using the static NumberFormat.getInstance( ) method. For example:

NumberFormat myFormat = NumberFormat.getInstance( ); NumberFormat canadaFormat = NumberFormat.getInstance(Locale.CANADA); Locale turkey = new Locale("tr", ""); NumberFormat turkishFormat = NumberFormat.getInstance(turkey);

The number format returned by NumberFormat.getInstance( ) should do a reasonable job of formatting most numbers. However, theres at least a theoretical possibility that the instance returned will format numbers as currencies or percentages. Therefore, it wouldn hurt to use NumberFormat.getNumberInstance( ) instead:

public static final NumberFormat getNumberInstance( ) public static NumberFormat getNumberInstance(Locale inLocale)

For example:

NumberFormat myFormat = NumberFormat.getNumberInstance( ); NumberFormat canadaFormat = NumberFormat.getNumberInstance(Locale.CANADA);

.3.1. Formatting Numbers

A NumberFormat object converts integers and floating-point numbers into formatted strings using one of five overloaded format( ) methods:

public final String format(long number) public final String format(double number) public abstract StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) public abstract StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) public final StringBuffer format(Object number, StringBuffer toAppendTo, FieldPosition pos)

These methods all return a string or a string buffer form of the number argument using the formats default formatting rules. These rules specify:

For any given number format, these rules can be quite complex. For instance, they may or may not take into account different digit characters, exponential or scientific notation, Roman numerals, or more. By creating new subclasses of NumberFormat, you can specify arbitrarily complex rules for converting binary numbers into strings. Regardless of exactly how a number format formats numbers, they are all manipulated the same way.

The last three format( ) methods append the string to the specified StringBuffer toAppendTo. They then return that modified string buffer. They use a java.text.FieldPosition object to provide information to the client programmer about where the different parts of the number fall. This will be discussed later. The final format( ) method formats instances of the numeric type wrapper classes, that is, java.lang.Double, java.lang.Float, java.lang.Long, java.lang.Integer, java.lang.Short, java.lang.Character, and java.lang.Byte. Some (but not all) NumberFormat objects may be able to format other kinds of numbers, like java.math.BigDecimal and java.math.BigInteger as well.

Example 21-1 is about the simplest use of NumberFormat imaginable. It uses the default number format for the default locale to print multiples of p. For comparison, both the formatted and unformatted numbers are printed.

Example 21-1. Multiples of pi

import java.text.*; public class FormatTest { public static void main(String[] args) { NumberFormat nf = NumberFormat.getInstance( ); for (double x = Math.PI; x < 100000; x *= 10) { String formattedNumber = nf.format(x); System.out.println(formattedNumber + " " + x); } } }

On my U.S. English system, the results look like this:

3.141 3.14159265358979 31.415 31.4159265358979 314.159 314.159265358979 3,141.592 3141.5926535897897 31,415.926 31415.926535897896

The formatted numbers don use a ridiculous number of decimal places and group the integer part with commas when it becomes large. Of course, the exact formatting depends on the default locale. For instance, when I changed the locale to French, I got this output:

3,141 3.14159265358979 31,415 31.4159265358979 314,159 314.159265358979 3 141,592 3141.5926535897897 31 415,926 31415.926535897896

The French locale uses a decimal comma instead of a decimal point and separates every three digits in the integer part with a space. This may be confusing to an American, but seems perfectly normal to a Parisian. One of the advantages of number formats is that by using the default number format for the system, much of your program is automatically localized. No extra code is required to do the right thing on French systems, on Canadian systems, on Japanese systems, and so on. However, if you know you want output in a particular locale, regardless of what the locale is on the current system, just pass the locale you desire to the getInstance( ) method. For instance, this requests a French NumberFormat:

NumberFormat format = NumberFormat.getInstance(Locale.FRENCH);

If no such format is installed, youll end up with the default locale anyway, but if a French locale is available you can now use it.

.3.2. Specifying Precision

Number formats have both a maximum and a minimum number of integer and fraction digits. For instance, in the number 31.415, there are two integer digits and three fraction digits. If the maximum number of digits in a part is less than the number actually present, the number is truncated (integer part) or rounded (fraction part). If the minimum is greater than the number of digits actually present, extra zeros are added to the beginning of the integer part or the end of the fraction part. For example, with a minimum of three integer digits and a maximum of two fraction digits, 31.415 would be formatted as 031.42.

You specify the minimum and maximum of each type you want in each number using these four methods:

public void setMaximumIntegerDigits(int newValue) public void setMinimumIntegerDigits(int newValue) public void setMaximumFractionDigits(int newValue) public void setMinimumFractionDigits(int newValue)

For example, to specify that myFormat should format numbers with at least 10 digits before the decimal point and at most 3 digits after, you would type:

myFormat.setMinimumIntegerDigits(10); myFormat.setMaximumFractionDigits(3);

Setting the minimum digits guarantees that those digits will be printed, filled with zeros if necessary. Setting the maximum digits allows the digits to be printed if they e nonzero or a place-holding zero (i.e., not the leftmost or rightmost digit). Leftmost and rightmost zeros will only be printed if necessary to fill the minimum number of digits. If you try to set a maximum below a minimum or a minimum above a maximum, the last one set takes precedence. Java raises the maximum to meet the minimum or lowers the minimum to meet the maximum.

Specifying the number of digits is useful when printing many columns of numbers in a tabular format to the console or in a monospaced font. Example 21-2 prints a three-column table of the angles between 0 and 360 degrees in degrees, radians and grads without any formatting.

Example 21-2. Ugly Table

public class UglyTable { public static void main(String[] args) { System.out.println("Degrees Radians Grads"); for (double degrees = 0.0; degrees < 360.0; degrees++) { double radians = Math.PI * degrees / 180.0; double grads = 400 * degrees / 360; System.out.println(degrees + " " + radians + " " + grads); } } }

Its output looks like this (not very pretty):

300.0 5.2359877559829835 333.3333333333333 301.0 5.253441048502927 334.44444444444446 302.0 5.27089434102287 335.55555555555554 303.0 5.288347633542813 336.6666666666667 304.0 5.305800926062757 337.77777777777777 305.0 5.3232542185827 338.8888888888889 306.0 5.340707511102643 340.0

Example 21-3 prints the same table with each number formatted to at least three integer digits and exactly two fraction digits (both minimum and maximum set to 2).

Example 21-3. Pretty Table

import java.text.*; public class PrettyTable { public static void main(String[] args) { System.out.println("Degrees Radians Grads"); NumberFormat myFormat = NumberFormat.getInstance( ); myFormat.setMinimumIntegerDigits(3); myFormat.setMaximumFractionDigits(2); myFormat.setMinimumFractionDigits(2); for (double degrees = 0.0; degrees < 360.0; degrees++) { String radianString = myFormat.format(Math.PI * degrees / 180.0); String gradString = myFormat.format(400 * degrees / 360); String degreeString = myFormat.format(degrees); System.out.println(degreeString + " " + radianString + " " + gradString); } } }

Its output looks like this (much nicer):

300.00 005.23 333.33 301.00 005.25 334.44 302.00 005.27 335.55 303.00 005.28 336.66 304.00 005.30 337.77 305.00 005.32 338.88 306.00 005.34 340.00 ...

Note that the extra integer digits are padded with zeros rather than spaces. Youll learn how to fix that shortly.

There are getMinimumIntegerDigits( ) and getMaximumIntegerDigits( ) methods that let you inspect the minimum and maximum number of digits provided by any number format, including the default:

public int getMaximumIntegerDigits( ) public int getMinimumIntegerDigits( ) public int getMaximumFractionDigits( ) public int getMinimumFractionDigits( )

.3.3. Grouping

How big is 299792500? You can easily tell because the number is hard to read. Its obviously a pretty big number, but at a glance you don know whether its in the ballpark of 3 million, 30 million, 300 million, or 3 billion. On the other hand, if its written as 299,792,500, its a lot more obvious that the number is about 300 million. The commas group different parts of the number. By counting the groups, you get a quick idea of the numbers order of magnitude.

Like other aspects of text formatting, different locales use different grouping conventions. In Belgium, Denmark, Holland, Spain, and Germany, a period groups thousands, and a comma is used as the "decimal point." Thus, the U.S. number 2,365,335.32 is equivalent to the Danish/Dutch number 2.365.335,32. Finnish uses an English-style decimal point but separates characters with a space rather than a comma. Thus, 2,365,335.32 is, in Finnish, 2 365 335.32. France, Sweden, and Norway also separate thousands with spaces but use a decimal comma: 2 365 335,32. Francophone Canada follows Frances convention, but Canadian Anglophones use the American-British convention. And in Switzerland, an apostrophe separates thousands in all four of its official languages: 2365335.32

Most number formats support grouping, and some use it by default. You may inquire whether a particular NumberFormat uses grouping with the isGroupingUsed( ) method:

public boolean isGroupingUsed( )

This method returns true if the format groups numbers or false if it doesn . You can turn grouping on or off for a number format with the setGroupingUsed( ) method:

public void setGroupingUsed(boolean groupNumbers)

Passing TRue turns grouping on. Passing false turns it off. Youll usually want to use grouping in strings that will be read by human beings and not use grouping in strings that will be parsed by computers.

.3.4. Currency Formats

Its not hard to tack on a dollar sign before a decimal number with two digits of precision. The NumberFormat class does a little more, handling international currencies with relative ease. For money, you can request the default locales currency formatter with the static NumberFormat.getCurrencyInstance( ) method:

public static final NumberFormat getCurrencyInstance( )

To get a currency formatter for a different locale, pass the locale to NumberFormat.getCurrencyInstance( ):

public static NumberFormat getCurrencyInstance(Locale inLocale)

Example 21-4 calculates the annual earnings of a worker making minimum wage in U.S. dollars. A currency format returned by NumberFormat.getCurrencyInstance(Locale.ENGLISH) formats the monetary quantities.

Example 21-4. Currency Formats

import java.text.*; import java.util.*; public class MinimumWage { public static void main(String[] args) { NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(Locale.ENGLISH); double minimumWage = 5.15; System.out.println("The minimum wage is " + dollarFormat.format(minimumWage)); System.out.println("A worker earning minimum wage and working for forty"); System.out.println("hours a week, 52 weeks a year, would earn " + dollarFormat.format(40*52*minimumWage)); } }

This program prints:

The minimum wage is $5.15 A worker earning minimum wage and working for forty hours a week, 52 weeks a year, would earn $10,712.00

Notice how nicely the numbers are formatted. Nowhere did I add dollar signs, say that I wanted exactly two numbers after the decimal point, or say that I wanted to separate the thousands with commas. The NumberFormat class took care of that.

There are limits to how far currency formatting goes. Currency formats may change the currency sign in different locales, but they won convert values (between U.S. and Canadian dollars or between U.S. dollars and British pounds, for example). Since conversion rates float from day to day and minute to minute, thats a bit much to ask of a fixed class. If you want to do this, you need to provide some source of the conversion rate information, either from user input or pulled off the network.

.3.5. Percent Formats

Number formats can also handle percentages in a variety of international formats. In grammar school you learned that a number followed by a percent sign is really one-hundredth of its apparent value. Thus, 50% is really decimal 0.5, 100% is 1.0, 10% is 0.1, and so on. Percent formats allow you to use the actual decimal values in your code but print out the hundred-times larger percent values in the output. You request the default locales percentage formatter with the static method NumberFormat.getPercentInstance( ):

public static final NumberFormat getPercentInstance( )

To get a percentage formatter for a different locale, pass the locale to NumberFormat.getPercentInstance( ):

public static NumberFormat getPercentInstance(Locale inLocale)

Example 21-5 prints a table of percents between 1% and 100%. Notice that doubles are used in the code, but integral percents appear in the output.

Example 21-5. PercentTable

import java.text.*; import java.util.*; public class PercentTable { public static void main(String[] args) { NumberFormat percentFormat = NumberFormat.getPercentInstance(Locale.ENGLISH); for (double d = 0.0; d <= 1.0; d += 0.005) { System.out.println(percentFormat.format(d)); } } }

Heres some of the output:

0% 0% 1% 1% 2% 2% 3% 3% 4% 4% ...

Notice that all percentage values are rounded to the nearest whole percent. This could be a problem if you need to format something like a tax rate. There is no 0.5% or 8.25% such as you might need when describing sales tax. To include fractional percents, call setMinimumFractionDigits( ) and setMaximumFractionDigits( ). For example:

NumberFormat percentFormat = NumberFormat.getPercentInstance(Locale.ENGLISH); percentFormat.setMaximumFractionDigits(2);

Категории

© amp.flylib.com,