Skip to content

Commit 81e3757

Browse files
author
Justin Lu
committed
8373566: Performance regression with java.text.MessageFormat subformat patterns
Reviewed-by: liach, rriggs, naoto
1 parent 76e79db commit 81e3757

File tree

2 files changed

+49
-37
lines changed

2 files changed

+49
-37
lines changed

src/java.base/share/classes/java/text/MessageFormat.java

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,12 +1713,7 @@ private Format formatFromPattern(String type, String style) {
17131713
throw new IllegalArgumentException("unknown format type: " + type);
17141714
}
17151715
// Get the style if recognized, otherwise treat style as a SubformatPattern
1716-
FormatStyle fStyle;
1717-
try {
1718-
fStyle = FormatStyle.fromString(style);
1719-
} catch (IllegalArgumentException iae) {
1720-
fStyle = FormatStyle.SUBFORMATPATTERN;
1721-
}
1716+
FormatStyle fStyle = FormatStyle.fromString(style);
17221717
return switch (fType) {
17231718
case NUMBER -> switch (fStyle) {
17241719
case DEFAULT -> NumberFormat.getInstance(locale);
@@ -1976,41 +1971,43 @@ private enum FormatType {
19761971
}
19771972

19781973
// Corresponding to the FormatStyle pattern
1974+
// WARNING: fromString is dependent on ordinal positioning and Enum names.
19791975
private enum FormatStyle {
1980-
DEFAULT(""),
1981-
SHORT("short"),
1982-
MEDIUM("medium"),
1983-
LONG("long"),
1984-
FULL("full"),
1985-
INTEGER("integer"),
1986-
CURRENCY("currency"),
1987-
PERCENT("percent"),
1988-
COMPACT_SHORT("compact_short"),
1989-
COMPACT_LONG("compact_long"),
1990-
OR("or"),
1991-
UNIT("unit"),
1992-
SUBFORMATPATTERN(null);
1993-
1994-
private final String text;
1995-
1996-
// Differs from FormatType in that the text String is
1997-
// not guaranteed to match the Enum name, thus a text field is used
1998-
FormatStyle(String text) {
1999-
this.text = text;
2000-
}
2001-
2002-
// This method returns a FormatStyle (excluding SUBFORMATPATTERN)
2003-
// that matches the passed String. If no FormatStyle is found,
2004-
// an IllegalArgumentException is thrown
1976+
// Special styles
1977+
DEFAULT,
1978+
SUBFORMATPATTERN,
1979+
// Pre-defined styles
1980+
SHORT,
1981+
MEDIUM,
1982+
LONG,
1983+
FULL,
1984+
INTEGER,
1985+
CURRENCY,
1986+
PERCENT,
1987+
COMPACT_SHORT,
1988+
COMPACT_LONG,
1989+
OR,
1990+
UNIT;
1991+
1992+
// Returns a FormatStyle corresponding to the input text.
1993+
// DEFAULT is the empty String.
1994+
// Pre-defined styles are lower case versions of their enum name
1995+
// (but compared case-insensitive for historical compatibility).
1996+
// SUBFORMATPATTERN is anything else.
20051997
private static FormatStyle fromString(String text) {
2006-
for (FormatStyle style : values()) {
2007-
// Also check trimmed case-insensitive for historical reasons
2008-
if (style != FormatStyle.SUBFORMATPATTERN &&
2009-
text.trim().compareToIgnoreCase(style.text) == 0) {
2010-
return style;
1998+
var style = text.trim();
1999+
if (style.isEmpty()) {
2000+
return FormatStyle.DEFAULT;
2001+
}
2002+
var styles = values();
2003+
// Match starting at the pre-defined styles -> [SHORT:]
2004+
for (int i = SHORT.ordinal(); i < styles.length; i++) {
2005+
var fStyle = styles[i];
2006+
if (style.compareToIgnoreCase(fStyle.name()) == 0) {
2007+
return fStyle;
20112008
}
20122009
}
2013-
throw new IllegalArgumentException();
2010+
return FormatStyle.SUBFORMATPATTERN;
20142011
}
20152012
}
20162013

test/micro/org/openjdk/bench/java/text/MessageFormatterBench.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
23
* Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved.
34
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
45
*
@@ -51,6 +52,8 @@
5152
public class MessageFormatterBench {
5253

5354
private Object[][] values;
55+
private String choicePattern;
56+
private String numberPattern;
5457

5558
@Setup
5659
public void setup() {
@@ -60,6 +63,8 @@ public void setup() {
6063
new Object[]{Double.valueOf(123.89), "MyDisk3"},
6164
new Object[]{Long.valueOf(1234567), "MyDisk4"},
6265
};
66+
choicePattern = "{0,choice,0#|1#{1}|2#{1} ({2})}";
67+
numberPattern = "{0,number,000}";
6368
}
6469

6570
private MessageFormat messageFormat = new MessageFormat("There is {0} GB of free space on the {1}.", Locale.ENGLISH);
@@ -72,6 +77,16 @@ public void testMessageFormat(final Blackhole bh) {
7277
}
7378
}
7479

80+
@Benchmark
81+
public MessageFormat testSubformatChoice() {
82+
return new MessageFormat(choicePattern);
83+
}
84+
85+
@Benchmark
86+
public MessageFormat testSubformatNumber() {
87+
return new MessageFormat(numberPattern);
88+
}
89+
7590
public static void main(String... args) throws Exception {
7691
Options opts = new OptionsBuilder().include(MessageFormatterBench.class.getSimpleName()).shouldDoGC(true).build();
7792
new Runner(opts).run();

0 commit comments

Comments
 (0)