<div dir="ltr"><br>Hi , Chen Liang <div>Thanks for the clarification. </div><div>I agree this IllegalArgumentException is an internal exception used for control flow; it’s not printed externally by default. </div><div>However, if it is thrown/caught frequently on a hot path, it can still incur a noticeable overhead (e.g., fillInStackTrace).</div><div><br>We were able to notice this because our team monitors common JDK internal exceptions in our production workloads to validate whether changes in each release match our expectations. </div><div>So even though this exception is not normally surfaced, we still observed the behavior.</div><div><br>Below I’m adding a more concrete reproduction and benchmark data, for your evaluation of whether this is worth addressing/backporting in 25u.</div><div><br>## Reproducible benchmark (JMH) and results (JDK 21 vs JDK 25)</div><div>I wrote a minimal JMH benchmark to simulate the cost of this pattern:</div><div>```</div><div><div style="background-color:rgb(30,31,34);color:rgb(188,190,196)"><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><span style="color:rgb(207,142,109)">private static final </span>String <span style="color:rgb(199,125,187);font-style:italic">CHOICE_PATTERN </span>= <span style="color:rgb(106,171,115)">"{0,choice,0#|1#{1}|2#{1} ({2})}"</span>;<br><br><span style="color:rgb(179,174,96)">@Param</span>({<span style="color:rgb(106,171,115)">"0"</span>, <span style="color:rgb(106,171,115)">"1"</span>, <span style="color:rgb(106,171,115)">"2"</span>})<br><span style="color:rgb(207,142,109)">public int </span><span style="color:rgb(199,125,187)">choiceValue</span>;<br><br><span style="color:rgb(207,142,109)">private </span>Object[] <span style="color:rgb(199,125,187)">args</span>;<br><br><span style="color:rgb(179,174,96)">@Setup</span>(Level.<span style="color:rgb(199,125,187);font-style:italic">Iteration</span>)<br><span style="color:rgb(207,142,109)">public void </span><span style="color:rgb(86,168,245)">setup</span>() {<br> <span style="color:rgb(199,125,187)">args </span>= <span style="color:rgb(207,142,109)">new </span>Object[]{<span style="color:rgb(199,125,187)">choiceValue</span>, <span style="color:rgb(106,171,115)">"us_en"</span>, <span style="color:rgb(106,171,115)">"UTF-8"</span>};<br>}<br><span style="color:rgb(95,130,107);font-style:italic"><br></span><span style="color:rgb(179,174,96)">@Benchmark<br></span><span style="color:rgb(207,142,109)">public void </span><span style="color:rgb(86,168,245)">messageFormat_choice_static</span>(Blackhole bh) {<br> String result = MessageFormat.<span style="font-style:italic">format</span>(<span style="color:rgb(199,125,187);font-style:italic">CHOICE_PATTERN</span>, <span style="color:rgb(199,125,187)">args</span>);<br> bh.consume(result);<br>}</pre></div></div><div>```</div><div><br>Pattern: {0,choice,0#|1#{1}|2#{1} ({2})}<br>Method: call MessageFormat.format(pattern, args) (creates a new MessageFormat instance and parses the pattern each time) to amplify parsing/branch costs; 1 thread; warmup 3x10s; measurement 5x10s; fork 1.<br>Key results (Throughput, ops/ms):</div><div><br>JDK 21.0.5: ~2379 to ~3204 ops/ms (depending on choiceValue = 0/1/2)<br>JDK 25: ~866 to ~1029 ops/ms</div><div><br></div><div>```</div><div><div style="background-color:rgb(30,31,34);color:rgb(188,190,196)"><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><span style="color:rgb(207,142,109)"># </span>JMH version: 1.37<br><span style="color:rgb(207,142,109)"># </span>VM version: JDK 21.0.5, OpenJDK 64-Bit Server VM, 21.0.5+11-LTS<br></pre><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><div><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><span style="color:rgb(207,142,109)"># </span>Warmup: 3 iterations, 10 s each<br><span style="color:rgb(207,142,109)"># </span>Measurement: 5 iterations, 10 s each<br><span style="color:rgb(207,142,109)"># </span>Timeout: 10 min per iteration<br><span style="color:rgb(207,142,109)"># </span>Threads: 1 thread, will synchronize iterations<br><span style="color:rgb(207,142,109)"># </span>Benchmark mode: Throughput, ops/time</pre><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><br></pre><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><div><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt">Benchmark (choiceValue) Mode Cnt Score Error Units<br>MessageFormatBench.messageFormat_choice_static 0 thrpt 5 3204.770 ± 343.887 ops/ms<br>MessageFormatBench.messageFormat_choice_static 1 thrpt 5 2513.444 ± 380.943 ops/ms<br>MessageFormatBench.messageFormat_choice_static 2 thrpt 5 2379.665 ± 152.148 ops/ms</pre></div></pre></div></pre></div></div><div>```</div><div><br></div><div><br></div><div>```</div><div><div style="background-color:rgb(30,31,34);color:rgb(188,190,196)"><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><span style="color:rgb(207,142,109)"># </span>JMH version: 1.37<br><span style="color:rgb(207,142,109)"># </span>VM version: JDK 25, OpenJDK 64-Bit Server VM, 25+36-3489<br></pre><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><br></pre><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><span style="color:rgb(207,142,109)"># </span>Warmup: 3 iterations, 10 s each<br><span style="color:rgb(207,142,109)"># </span>Measurement: 5 iterations, 10 s each<br><span style="color:rgb(207,142,109)"># </span>Timeout: 10 min per iteration<br><span style="color:rgb(207,142,109)"># </span>Threads: 1 thread, will synchronize iterations<br><span style="color:rgb(207,142,109)"># </span>Benchmark mode: Throughput, ops/time<br></pre><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><div><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt">Benchmark (choiceValue) Mode Cnt Score Error Units<br>MessageFormatBench.messageFormat_choice_static 0 thrpt 5 1029.018 ± 16.425 ops/ms<br>MessageFormatBench.messageFormat_choice_static 1 thrpt 5 932.762 ± 12.648 ops/ms<br>MessageFormatBench.messageFormat_choice_static 2 thrpt 5 866.487 ± 49.584 ops/ms<br></pre></div></pre></pre></div></div><div>```</div><div><br>This is roughly a 2.5x–3.1x throughput regression on JDK 25 compared to JDK 21.</div><div><br>Note: the benchmark configuration is consistent between the two runs.</div><div><br>Best regards,<br>Vincent Gao<br></div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">Chen Liang <<a href="mailto:chen.l.liang@oracle.com">chen.l.liang@oracle.com</a>> 于2025年12月12日周五 00:52写道:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="msg3859596206615380740">
<div dir="ltr">
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
Hello Vincent Gao,</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
I saw your Java Bugs submission. Unfortunately your stacktrace caused some confusion to our triage because it is an internal exception and that trace is never printed anywhere.</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
Your suggestion is a reasonable enhancement, that we should not use ad-hoc exceptions for control flow, given they need to fill stack traces, which is extremely costly.</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
Since this is a cleanup, we might commit this to mainline JDK first. If this proves to be a performance bottleneck on 25 updates, we can backport.</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
Since you are writing here, I assume this has a non-negligible impact on performance.</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
If you can share a flame graph showing the regression from this exception, or a benchmark difference between 21 and 25.0.1, this would be extremely helpful.</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
<br>
</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
Regards,</div>
<div style="font-family:"Calibri Light","Helvetica Light",sans-serif;font-size:12pt;color:rgb(0,0,0)">
Chen Liang</div>
<div id="m_-4234814211421836574appendonsend"></div>
<hr style="display:inline-block;width:98%">
<div id="m_-4234814211421836574divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" style="font-size:11pt" color="#000000"><b>From:</b> core-libs-dev <<a href="mailto:core-libs-dev-retn@openjdk.org" target="_blank">core-libs-dev-retn@openjdk.org</a>> on behalf of weigao <<a href="mailto:china.weigao@gmail.com" target="_blank">china.weigao@gmail.com</a>><br>
<b>Sent:</b> Wednesday, December 10, 2025 9:31 PM<br>
<b>To:</b> <a href="mailto:core-libs-dev@openjdk.org" target="_blank">core-libs-dev@openjdk.org</a> <<a href="mailto:core-libs-dev@openjdk.org" target="_blank">core-libs-dev@openjdk.org</a>><br>
<b>Subject:</b> Re: [External] Feedback JDK-8318761 : Potential Issue in JDK 25 MessageFormat: Use of Internal Exception for Control Flow</font>
<div> </div>
</div>
<div>
<div dir="ltr">
<div dir="ltr">hi , because of ``<span style="font-family:"JetBrains Mono",monospace;font-size:9.8pt;background-color:rgb(30,31,34);color:rgb(207,142,109)">private static </span><span style="font-family:"JetBrains Mono",monospace;font-size:9.8pt;background-color:rgb(30,31,34);color:rgb(188,190,196)">FormatStyle </span><span style="font-family:"JetBrains Mono",monospace;font-size:9.8pt;background-color:rgb(30,31,34);color:rgb(86,168,245)">fromString</span><span style="font-family:"JetBrains Mono",monospace;font-size:9.8pt;background-color:rgb(30,31,34);color:rgb(188,190,196)">(String
text)</span>` throw exception and the try catch exception just set the deault value `<span style="font-family:"JetBrains Mono",monospace;font-size:9.8pt;background-color:rgb(30,31,34);color:rgb(188,190,196)">FormatStyle.</span><span style="font-family:"JetBrains Mono",monospace;font-size:9.8pt;background-color:rgb(30,31,34);color:rgb(199,125,187);font-style:italic">SUBFORMATPATTERN</span>`
, so why just make this function retuen this value like ? Is it better , right ?</div>
<div dir="ltr">```</div>
<div dir="ltr">
<div style="background-color:rgb(30,31,34);color:rgb(188,190,196)">
<pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><span style="color:rgb(207,142,109)">private static </span>FormatStyle <span style="color:rgb(86,168,245)">fromString</span>(String text) {<br> <span style="color:rgb(207,142,109)">for </span>(FormatStyle style : <span style="font-style:italic">values</span>()) {<br> <span style="color:rgb(122,126,133)">// Also check trimmed case-insensitive for historical reasons<br></span><span style="color:rgb(122,126,133)"> </span><span style="color:rgb(207,142,109)">if </span>(style != FormatStyle.<span style="color:rgb(199,125,187);font-style:italic">SUBFORMATPATTERN </span>&&<br> text.trim().compareToIgnoreCase(style.<span style="color:rgb(199,125,187)">text</span>) == <span style="color:rgb(42,172,184)">0</span>) {<br> <span style="color:rgb(207,142,109)">return </span>style;<br> }<br> }<br> <span style="color:rgb(207,142,109)">return </span>FormatStyle.<span style="color:rgb(199,125,187);font-style:italic">SUBFORMATPATTERN</span>;<br>}</pre>
</div>
</div>
<div dir="ltr">```</div>
<br>
<div>
<div dir="ltr">weigao <<a href="mailto:china.weigao@gmail.com" target="_blank">china.weigao@gmail.com</a>> 于2025年12月11日周四 11:21写道:<br>
</div>
<blockquote style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div dir="ltr">
<p>Hello,</p>
<p>I would like to report a potential design issue in the JDK 25 implementation of
<code>MessageFormat</code>.</p>
<p>While working with <code>java.util.Locale#getDisplayName()</code>, I found that JDK internals throw and catch an
<code>IllegalArgumentException</code> due to the following pattern added in the resource bundles:</p>
<ul>
<li>
<p><code>sun.util.resources.cldr.LocaleNames</code></p>
</li><li>
<p><code>sun.util.resources.LocaleNames</code></p>
</li></ul>
<p>The pattern in question is:</p>
<pre><div><div><div><div></div></div></div><div dir="ltr"><code><span>DisplayNamePattern:</span> {<span>0</span>,<span>choice</span>,<span>0</span><span>#|1#{1}|2#{1} ({2})}</span>
</code></div></div></pre>
<p>This change originates from the following commit:<br>
<code>adoptium/jdk@00ffc42</code> — which adds a pattern for <code>MessageFormat</code>.<br>
However, <code>choice</code> is <strong>not</strong> a valid type for <code>FormatStyle</code>.</p>
<p>As a result, calling <code>Locale#getDisplayName()</code> triggers the following exception inside JDK code:</p>
<pre><div><div><div><div></div></div></div><div dir="ltr"><code>java.lang.IllegalArgumentException
at java.base/java.text.MessageFormat<span>$FormatStyle</span>.fromString(MessageFormat.java:2013)
at java.base/java.text.MessageFormat.formatFromPattern(MessageFormat.java:1718)
at java.base/java.text.MessageFormat.setFormatFromPattern(MessageFormat.java:1679)
at java.base/java.text.MessageFormat.applyPatternImpl(MessageFormat.java:660)
at java.base/java.text.MessageFormat.<init>(MessageFormat.java:516)
at java.base/java.util.Locale.getDisplayName(Locale.java:2309)
</code></div></div></pre>
<p>The implementation currently relies on exception-based logic:</p>
<pre><div><div><div><div></div></div></div><div dir="ltr"><code><span>try</span> {
fStyle = FormatStyle.fromString(style);
} <span>catch</span> (IllegalArgumentException iae) {
fStyle = FormatStyle.SUBFORMATPATTERN;
}
</code></div></div></pre>
<p>I understand that <code>MessageFormat</code> catches this exception and falls back to
<code>SUBFORMATPATTERN</code>, but using exceptions to control expected logic paths may not be ideal—especially since
<code>FormatStyle.fromString()</code> is only used by <code>MessageFormat</code>.</p>
<p>A potentially cleaner approach could be to have <code>FormatStyle.fromString()</code> return
<code>FormatStyle.SUBFORMATPATTERN</code> directly when encountering unknown style identifiers, instead of throwing an exception.</p>
<p><strong>JDK Version Observed:</strong></p>
<pre><div><div><div><div></div></div></div><div dir="ltr"><code>OpenJDK Runtime Environment Temurin-<span>25.0</span><span>.1</span>+<span>8</span> (build <span>25.0</span>.<span>1</span>+<span>8</span>-LTS)
</code></div></div></pre>
<p>Please let me know if this behavior is intentional, or if it should be considered for improvement.</p>
<p>Best regards,<br>
vincent gao</p>
</div>
</blockquote>
</div>
</div>
</div>
</div>
</div></blockquote></div>