Explicit Formats
Home ] Up ] MessageFormat ] [ Explicit Formats ] Summary of Patterns ] Formatting Numbers ]

 

 

We can change the way each object is displayed in the formatted string, by:

  • Adding placeholder information to the string itself, or
  • Calling the appropriate setFormat or setFormats method

Using the setFormat method

Here's how to do it by calling setFormat methods

package inputOutput;

import java.text.MessageFormat;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.GregorianCalendar;

public class FormatText
{
    public static void main(String[] args)
    {
        String pattern = 
         "On {2}, a {0} destroyed {1} houses and caused {3} of damage.";
        MessageFormat msgFormat = new MessageFormat(pattern);
        msgFormat.setFormat(0, DateFormat.getDateInstance(DateFormat.LONG));
        msgFormat.setFormat(3, NumberFormat.getCurrencyInstance());
        Object[] msgArgs =
        { 
            "hurricane", 
            new Integer(99), 
            new GregorianCalendar(1999, 0, 1).getTime(),
            new Double(10E7)
        };
        System.out.println(msgFormat.format(msgArgs));
    }
}

which produces:

On January 1, 1999, a hurricane destroyed 99 houses and caused $100,000,000.00 of damage.

Using the setFormats method

We could have accomplished the same thing as follows:

package inputOutput;

import java.text.MessageFormat;
import java.text.DateFormat;
import java.text.Format;
import java.text.NumberFormat;
import java.util.GregorianCalendar;

public class FormatText
{
    public static void main(String[] args)
    {
        String pattern = 
         "On {2}, a {0} destroyed {1} houses and caused {3} of damage.";
        MessageFormat msgFormat = new MessageFormat(pattern);
        Format argFormats[] =
        {
            DateFormat.getDateInstance(DateFormat.LONG),
            null,
            null,
            NumberFormat.getCurrencyInstance()
        };
        msgFormat.setFormats(argFormats);
        Object[] msgArgs =
        { 
            "hurricane", 
            new Integer(99), 
            new GregorianCalendar(1999, 0, 1).getTime(),
            new Double(10E7)
        };
        System.out.println(msgFormat.format(msgArgs));
    }
}

You can repeat the same argument, but with a different format:

package inputOutput;

import java.text.MessageFormat;
import java.text.DateFormat;
import java.text.Format;
import java.util.GregorianCalendar;

public class FormatText
{
    public static void main(String[] args)
    {
        String pattern = 
         "On {2}, a {0} touched down at {2} and destroyed {1} houses.";
        MessageFormat msgFormat = new MessageFormat(pattern);
        Format argFormats[] =
        {
            DateFormat.getDateInstance(DateFormat.LONG),
            null,
            DateFormat.getTimeInstance(DateFormat.SHORT),
            null
        };
        msgFormat.setFormats(argFormats);
        Object[] msgArgs =
        { 
            "tornado", 
            new Integer(99), 
            new GregorianCalendar(1999, 0, 1).getTime()
        };
        System.out.println(msgFormat.format(msgArgs));
    }
}

which outputs:

On January 1, 1999, a tornado touched down at 12:00 AM and destroyed 99 houses.

Note: The argument formats correspond to the position of the placeholder, while the message arguments correspond to the number of the placeholder.

Specifying Formats in the Placeholder

Another way of controlling the format is to specify the formats in the placeholder itself:

package inputOutput;

import java.text.MessageFormat;
import java.util.GregorianCalendar;

public class FormatText
{
    public static void main(String[] args)
    {
        String pattern = 
         "On {2,date,long}, a {0} touched down at {2,time,short}, " +
         "destroyed {1} houses, and caused {3,number,currency} of damage.";
        MessageFormat msgFormat = new MessageFormat(pattern);
        Object[] msgArgs =
        { 
            "tornado", 
            new Integer(99), 
            new GregorianCalendar(1999, 0, 1).getTime(),
            new Double(10E7)
        };
        System.out.println(msgFormat.format(msgArgs));
    }
}

which produces:

On January 1, 1999, a tornado touched down at 12:00 AM, destroyed 99 houses, and caused $100,000,000.00 of damage.

Choice Formats

Consider the following modification of the above program:

package inputOutput;

import java.text.MessageFormat;
import java.util.GregorianCalendar;

public class FormatText
{
    public static void main(String[] args)
    {
        String pattern = 
         "On {2,date,long}, a {0} " +
         "destroyed {1} houses, and caused {3,number,currency} of damage.";
        MessageFormat msgFormat = new MessageFormat(pattern);
        Object[] msgArgs =
        { 
            "earthquake", 
            new Integer(1), 
            new GregorianCalendar(1999, 0, 1).getTime(),
            new Double(10E7)
        };
        System.out.println(msgFormat.format(msgArgs));
    }
}

This outputs the string:

On January 1, 1999, a earthquake destroyed 1 houses, and caused $100,000,000.00 of damage.

which should, to be grammatically correct, read:

On January 1, 1999, an earthquake destroyed 1 house, and caused $100,000,000.00 of damage.

In other words, we have to deal with plurals correctly, as well as ensuring that parts of speech match properly (such as indefinite articles, etc.). This can be more important and more complex in other languages such as German or French, where articles must match the gender and context of a noun.

ChoiceFormat was designed to let you solve this problem. You must specify:

  • An array of limits
  • An array of format strings

Here's an example of how to solve the above problem:

package inputOutput;

import java.text.ChoiceFormat;
import java.text.MessageFormat;
import java.util.GregorianCalendar;

public class FormatText
{
    public static void main(String[] args)
    {
        double[] limits = {1, 1, 2};
        String[] formatStrings = 
		{"no houses", "one house", 
                    "{1,number,integer} houses"};
        ChoiceFormat choiceFormat = 
			new ChoiceFormat(limits, formatStrings);
        String pattern = 
         "On {2,date,long}, {0} " +
         "destroyed {1}, and caused {3,number,currency} of damage.";
        MessageFormat msgFormat = new MessageFormat(pattern);
        msgFormat.setFormat(2, choiceFormat);
        Object[] msgArgs =
        { 
            "an earthquake", 
            new Integer(1), 
            new GregorianCalendar(1999, 0, 1).getTime(),
            new Double(10E7)
        };
        System.out.println(msgFormat.format(msgArgs));
    }
}

which outputs:

On January 1, 1999, an earthquake destroyed one house, and caused $100,000,000.00 of damage.

Or, we can embed the same choices into the placeholders themselves:

package inputOutput;

import java.text.MessageFormat;
import java.util.GregorianCalendar;

public class FormatText
{
    public static void main(String[] args)
    {
        String pattern = 
         "On {2,date,long}, {0} destroyed " +
         "{1,choice,0#no houses|1#one house|2#{1,number,integer} houses}, " +
         "and caused {3,number,currency} of damage.";
        MessageFormat msgFormat = new MessageFormat(pattern);
        Object[] msgArgs =
        { 
            "an earthquake", 
            new Integer(1), 
            new GregorianCalendar(1999, 0, 1).getTime(),
            new Double(10E7)
        };
        System.out.println(msgFormat.format(msgArgs));
    }
}

This is actually far preferred, because it means that we can remove the message(s) from the program, and provide separate sets of messages for each language/locale, and have the separated messages contain all the necessary instructions to format the messages correctly in each language.  That way, the program does not have special code for each language.

Believe me, this is very important when you are writing code that will have to be internationalized (globalization is here, already!)

 

The page was last updated February 19, 2008