Igor's Techno Club

Java String.format vs MessageFormat

When it comes to string formatting in Java, developers typically opt for either straightforward string concatenation or the String.format method. I usually recommend using String.format, because it's less error prone than string concatenation, but today I want to explore another option that is often overlooked by developers.

The main difference between MessageFormat.format and String.format lies in how arguments are passed to the string: String.format utilizes specific placement markers (e.g., %s, %d), whereas MessageFormat.format uses indexed placeholders, with each index corresponding to a value from the argument array.

String message = "Hello, {0}! Welcome to {1}.";
String formattedMessage = MessageFormat.format(message, "John", "our website");
System.out.println(formattedMessage);

Output:

Hello, John! Welcome to our website.

But there are more differences to consider. Let's delve deeper into what MessageFormat.format offers:

Handling Pluralization:

String pattern = "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files} on your desktop.";
for (int count : new int[]{0, 1, 5}) {
    System.out.println(MessageFormat.format(pattern, count));
}

Output:

There are no files on your desktop.
There is one file on your desktop.
There are 5 files on your desktop.

Here, MessageFormat utilizes the choice format to select the appropriate message based on the number.

Localization and Internationalization:

double payment = 1234.56;
Object[] args = {payment};

MessageFormat usFormatted = new MessageFormat("The payment due is {0,number,currency}.", Locale.US);
MessageFormat itFormatted = new MessageFormat("The payment due is {0,number,currency}.", Locale.ITALY);

System.out.println(usFormatted.format(args));
System.out.println(itFormatted.format(args)); 

Output:

The payment due is $1,234.56.
The payment due is € 1.234,56.

MessageFormat.format supports localization by allowing the specification of a Locale object. In this example, the payment amount is formatted differently based on the locale.

Handling Date and Time Formatting

String message = "The meeting is scheduled for {0, date, long} at {0, time, short}.";
Date meetingDate = new Date();
String formattedMessage = MessageFormat.format(message, meetingDate);
System.out.println(formattedMessage);

Output:

The meeting is scheduled for May 18, 2023 at 10:30 AM.

MessageFormat.format can also handle date and time formatting based on specified format styles. In this example, the meeting date is formatted using the long date style and short time style. This method also allows for more sophisticated date formatting, such as:

Date now = new Date();
String formattedFilename = MessageFormat.format("file{0,date,yyyy-MM-dd-HH-mm-ss}.json", now);
System.out.println(formattedFilename);

Percent literal escaping

If dealt with escaping of percent sign in String.format case you may remember how awkward it may look like. The percent sign has a special meaning in string format patterns, serving as a placeholder for arguments. To include a literal percent sign in the formatted string, you need to escape it by doubling it up as %%.

Let's consider a real-world scenario where you might need to use string formatting with percent signs. Suppose you're developing a financial application that calculates the percentage change in stock prices.

Here's an example that demonstrates the usage of escaped percent signs in string formatting:

String stockName = "ABC Inc.";
double previousPrice = 100.00;
double currentPrice = 120.50;
double percentChange = (currentPrice - previousPrice) / previousPrice * 100;

String formattedOutput = String.format("%s stock price changed by %.2f%%", stockName, percentChange);
System.out.println(formattedOutput);
// Output: ABC Inc. stock price changed by 20.50%

String trendMessage;
if (percentChange > 0) {
    trendMessage = String.format("The stock price increased by %.2f%% compared to the previous price.", percentChange);
} else if (percentChange < 0) {
    trendMessage = String.format("The stock price decreased by %.2f%% compared to the previous price.", Math.abs(percentChange));
} else {
    trendMessage = "The stock price remained unchanged.";
}
System.out.println(trendMessage);
// Output: The stock price increased by 20.50% compared to the previous price.

Meanwhile, using MessageFormat.format() provides a more flexible and powerful way to create formatted messages.

In the following example, we use {1,number,#.##%} to format the percentage change as a number with two decimal places and a percent sign. The #.## pattern specifies the number of decimal places, and the % suffix adds the percent sign to the formatted value:

// Using MessageFormat.format()
String messageTemplate = "{0} stock price changed by {1,number,#.##%} as of {2,date,yyyy-MM-dd}.";
String formattedMessage = MessageFormat.format(messageTemplate, stockName, percentChange / 100, new java.util.Date());
System.out.println(formattedMessage);
// Output: ABC Inc. stock price changed by 20.50% as of 2023-06-09.

Conclusion

This exploration of MessageFormat.format demonstrates its flexibility and power, particularly in applications requiring localization, conditional formatting, and the management of complex string patterns.

#codequality #java #til