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.

Java String format recap

Before diving into the differences, let's first recap the main features of Java String.format and how it works.

String.format() uses a "format string" as the first argument, containing placeholders (format specifiers) that define how subsequent arguments are formatted:

String formattedString = String.format(formatString, argument1, argument2, ...);

formatString supports a wide range of format specifiers, each designed for specific data types and output formats. Here's an expanded list of commonly used specifiers:

Specifier Data Type Description Example Output
%s Any type String value "Hello, World!"
%d integer Decimal Integer 123
%f floating point Decimal number 3.14159
%a floating point Hexadecimal floating-point 0x1.921fb54442d18p1
%b Any type Boolean (true or false) true
%c character Unicode character A
%e floating point Scientific notation 3.141593e+00
%g floating point General scientific notation 3.14159
%h Any type Hexadecimal hash code 42a19a
%n None Platform-specific line separator \n
%o integer Octal number 173
%t Date/Time Date/Time (prefix for Date/Time conversions) Various formats
%x integer Hexadecimal string 7b

Examples:

String name = "Alice";
int age = 30;
double height = 5.8;
String formatted = String.format("Name: %s, Age: %d, Height: %.1f ft", name, age, height);
// Output: "Name: Alice, Age: 30, Height: 5.8 ft"
LocalDateTime now = LocalDateTime.now();
String formatted = String.format("Date: %tF, Time: %tT", now, now);
// Output: "Date: 2023-04-15, Time: 14:30:45"

Like the article so far? Support the author

Patreon


MessageFormat.format

The main difference between MessageFormat.format and String.format (or more recent "str".formatted() notation) 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.


Subscribe to the newsletter:



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.

What's next

Checkout my latest post about Java

#codequality #java #til