Formatting Numbers in Java

Before we reproduce Sun's own Tech tips on the subject, here is a Quick and dirty "format" method that could ease some problems. It converts a floating point value (X) to a string of given size (w) with a specified number (n) of decimals. If the value of W is negative, then number is aligned to the left otherwise it is aligned on the right. First an example of use:
   double x = 1.0 / 7;
   for (int n = 1; n<5; n++)
      System.out.println( "1/7 : "  + format( x, n, -6) 
                                    + format( x, n, 10));
This is the output:
     1/7 : 0.1          0.1
     1/7 : 0.14        0.14
     1/7 : 0.143      0.143
     1/7 : 0.1429    0.1429
And now the method
	static final String ZEROES = "000000000000";
	static final String BLANKS = "            ";
	
	static String format( double val, int n, int w) 
	{
	//	rounding			
		double incr = 0.5;
		for( int j=n; j>0; j--) incr /= 10; 
		val += incr;
		
		String s = Double.toString(val);
		int n1 = s.indexOf('.');
		int n2 = s.length() - n1 - 1;
		
		if (n>n2)      s = s+ZEROES.substring(0, n-n2);
		else if (n2>n) s = s.substring(0,n1+n+1);

		if( w>0 & w>s.length() ) s = BLANKS.substring(0,w-s.length()) + s;
		else if ( w<0 & (-w)>s.length() ) {
			w=-w;
			s = s + BLANKS.substring(0,w-s.length()) ;
		}
		return s;
	}	
A more complete Formatting package can be found in Util.java


Guy Lapalme also wrote up some tips.

CLICK for Guy's FIX


From Sun Tech Tips
Suppose that you're developing a Java(tm) application that uses 
decimal numbers, and you'd like to control the formatting of 
these numbers for output purposes. How do you do this using the 
Java library?

Or perhaps you don't care about formatting, but you do care about
making your application work in an international context. For
example, a simple statement like:

    System.out.println(1234.56);

is locale-dependent; "." is used as a decimal point in the United
States, but not necessarily everywhere else. How do you deal with
this concern?

A couple of classes in the java.text package deal with these kinds
of issues. Here's a simple example that uses these classes to
tackle the problem mentioned in the previous paragraph:

    import java.text.NumberFormat;
    import java.util.Locale;

    public class DecimalFormat1 {
        public static void main(String args[]) {

            // get format for default locale

            NumberFormat nf1 = NumberFormat.getInstance();
            System.out.println(nf1.format(1234.56));

            // get format for German locale

            NumberFormat nf2 =
                NumberFormat.getInstance(Locale.GERMAN);
            System.out.println(nf2.format(1234.56));
        }
    }

If you live in the United States and run this program, the output
is:

    1,234.56
    1.234,56

In other words, different locales, in this case locales for the
United States and for Germany, use different conventions for
representing numbers.

NumberFormat.getInstance returns an instance of NumberFormat
(actually a concrete subclass of NumberFormat such as
DecimalFormat), that is suited for formatting numbers according 
to the default locale. You can also specify a non-default locale, 
such as "Locale.GERMAN". Then the format method is called to 
format a number according to the rules of a specific locale.

Note that the program could have done the formatting using 
a single expression:

    NumberFormat.getInstance().format(1234.56)

but it's more efficient to save a format and then reuse it.

Internationalization is a big issue when formatting numbers. 
Another is the ability to exercise fine control over formatting,
for example, by specifying the number of decimal places. Here's
another example that illustrates this idea:

    import java.text.DecimalFormat;
    import java.util.Locale;

    public class DecimalFormat2 {
        public static void main(String args[]) {

            // get format for default locale

            DecimalFormat df1 = new DecimalFormat("####.000");
            System.out.println(df1.format(1234.56));

            // get format for German locale

            Locale.setDefault(Locale.GERMAN);
            DecimalFormat df2 = new DecimalFormat("####.000");
            System.out.println(df2.format(1234.56));
        }
    }

In this example, a specific number format is set, using a notation
like "####.000". This pattern means "four places before the decimal 
point, which are empty if not filled, and three places after the 
decimal point, which are 0 if not filled". The output of this 
program is:

    1234.560
    1234,560

In a similar way, it's possible to control exponent formatting, for
example:

    import java.text.DecimalFormat;

    public class DecimalFormat3 {
        public static void main(String args[]) {
            DecimalFormat df = new DecimalFormat("0.000E0000");
            System.out.println(df.format(1234.56));
        }
    }

The output here is:

    1.235E0003

You can also work with percentages:

    import java.text.NumberFormat;

    public class DecimalFormat4 {
        public static void main(String args[]) {
            NumberFormat nf = NumberFormat.getPercentInstance();
            System.out.println(nf.format(0.47));
        }
    }

The output from this program is:

    47%

So far, you've seen various techniques for formatting numbers.
What about going the other direction, that is, reading and parsing 
strings that contain formatted numbers? Parsing support is included 
in NumberFormat. For example, you can say:

    import java.util.Locale;
    import java.text.NumberFormat;
    import java.text.ParseException;

    public class DecimalFormat5 {
        public static void main(String args[]) {

            // get format for default locale

            NumberFormat nf1 = NumberFormat.getInstance();
            Object obj1 = null;

            // parse number based on format

            try {
                obj1 = nf1.parse("1234,56");
            }
            catch (ParseException e1) {
                System.err.println(e1);
            }
            System.out.println(obj1);

            // get format for German locale

            NumberFormat nf2 =
                NumberFormat.getInstance(Locale.GERMAN);
            Object obj2 = null;

            // parse number based on format

            try {
                obj2 = nf2.parse("1234,56");
            }
            catch (ParseException e2) {
                System.err.println(e2);
            }
            System.out.println(obj2);
        }
    }

This example has two parts, both of them concerned with parsing 
an identical string: "1234,56". The first part uses the default 
locale, the second the German locale. When this program is run 
in the United States, the result is:

    123456
    1234.56

In other words, the string "1234,56" is interpreted as a large
integer "123456" in the United States, but as a decimal number
"1234.56" in the German locale.

There's one final point to be covered in this discussion of
formatting. In the examples above, DecimalFormat and NumberFormat
are both used. DecimalFormat is used to gain fine control over
formatting, while NumberFormat is used to specify a locale other 
than the default. How do you combine these two classes?

The answer centers around the fact that DecimalFormat is a
subclass of NumberFormat, a subclass whose instances are specific 
to a particular locale. So you can use NumberFormat.getInstance to
specify a locale, and then cast the resulting instance to a
DecimalFormat object. The documentation says that this technique
will work in the vast majority of cases, but that you need to
surround the cast with a try/catch block just in case it does not
(presumably in a very obscure case with an exotic locale). Such an
approach looks like this:

    import java.text.DecimalFormat;
    import java.text.NumberFormat;
    import java.util.Locale;

    public class DecimalFormat6 {
        public static void main(String args[]) {
            DecimalFormat df = null;

            // get a NumberFormat object and cast it to
            // a DecimalFormat object

            try {
                df = (DecimalFormat)
                    NumberFormat.getInstance(Locale.GERMAN);
            }
            catch (ClassCastException e) {
                System.err.println(e);
            }

            // set a format pattern

            df.applyPattern("####.00000");

            // format a number

            System.out.println(df.format(1234.56));
        }
    }

The getInstance method obtains the format, then applyPattern is
called to set a particular formatting pattern. The output of this
program is:

    1234,56000

If you don't care about internationalization, it makes sense to use
DecimalFormat directly.

QUICK FIX

In the example below, we print out two floats - x and y - with 3 decimals in fields of 8 characters. To do this, we first create a "DecimalFormat" object using a string to define the format; then the "format" method of this object is used to created the printable formatted string. Concretely, this means:
    import java.text.DecimalFormat;
    import java.text.DecimalFormatSymbols;

    float X,Y = .....;
    String format1 = "###0.000" ;  

    static DecimalFormat fm1 = new DecimalFormat( format1,
                                   new DecimalFormatSymbols(Locale.US));
    
    System.out.println("X=" + fm1.format(x) + ", Y=" + fm1.format(y));
    

In the example, we used the "Locale.US" to make sure that the PERIOD is used as decimal seperator. The characters that can be used in the format string are as follows:

     Symbol Meaning
     0      a digit
     #      a digit, zero shows as absent
     .      placeholder for decimal separator
     ,      placeholder for grouping separator.
     E      separates mantissa and exponent for exponential formats.
     -      default negative prefix.
     %      multiply by 100 and show as percentage
     X      any other characters can be used in the prefix or suffix
     '      used to quote special characters in a prefix or suffix.
Suggested by Guy Lapalme's suggestion