UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

156 lines (151 loc) 25.1 kB
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><title>Formatting with the java.text Package</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Formatting with the java.text Package"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-10-SECT-6"/>Formatting with the java.text Package</h1></div></div></div><p><a id="idx10528" class="indexterm"/> <a id="idx10578" class="indexterm"/>The <code class="literal">java.text</code> package includes, among other things, a set of classes designed for generating and parsing string representations of objects. In this section, we’ll talk about three classes: <a id="I_indexterm10_id731170" class="indexterm"/><code class="literal">NumberFormat</code>, <a id="I_indexterm10_id731181" class="indexterm"/><code class="literal">ChoiceFormat</code>, and <a id="I_indexterm10_id731192" class="indexterm"/><code class="literal">MessageFormat</code>. <a class="xref" href="ch11.html" title="Chapter 11. Core Utilities">Chapter 11</a> describes the <code class="literal">DateFormat</code> class. As we said earlier, the classes of the <code class="literal">java.text</code> package overlap to a large degree with the capabilities of the <code class="literal">Scanner</code> and <code class="literal">printf</code>-style <code class="literal">Formatter</code>. Despite these new features, a number of areas in the parsing of currencies, dates, and times can only be handled with the <code class="literal">java.text</code> package.</p><p>The <code class="literal">NumberFormat</code> class can be used to format and parse currency, percentages, or plain old numbers. <code class="literal">NumberFormat</code> is an abstract class, but it has several useful factory methods that produce formatters for different types of numbers. For example, to format or parse currency strings, use <a id="I_indexterm10_id731256" class="indexterm"/><code class="literal">getCurrencyInstance()</code> :</p><a id="I_10_tt617"/><pre class="programlisting"> <code class="kt">double</code> <code class="n">salary</code> <code class="o">=</code> <code class="mf">1234.56</code><code class="o">;</code> <code class="n">String</code> <code class="n">here</code> <code class="o">=</code> <code class="c1">// $1,234.56</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getCurrencyInstance</code><code class="o">().</code><code class="na">format</code><code class="o">(</code><code class="n">salary</code><code class="o">);</code> <code class="n">String</code> <code class="n">italy</code> <code class="o">=</code> <code class="c1">// L 1.234,56</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getCurrencyInstance</code><code class="o">(</code><code class="n">Locale</code><code class="o">.</code><code class="na">ITALY</code><code class="o">).</code><code class="na">format</code><code class="o">(</code><code class="n">salary</code><code class="o">);</code></pre><p>The first statement generates an American salary, with a dollar sign, a comma to separate thousands, and a period as a decimal point. The second statement presents the same string in Italian, with a lire sign, a period to separate thousands, and a comma as a decimal point. Remember that <code class="literal">NumberFormat</code> worries about format only; it doesn’t attempt to do currency conversion. We can go the other way and parse a formatted value using the <code class="literal">parse()</code> method, as we’ll see in the next example.</p><p>Likewise, <a id="I_indexterm10_id731298" class="indexterm"/><code class="literal">getPercentInstance()</code> returns a formatter you can use for generating and parsing percentages. If you do not specify a <code class="literal">Locale</code> when calling a <code class="literal">getInstance()</code> method, the default <code class="literal">Locale</code> is used:</p><a id="I_10_tt618"/><pre class="programlisting"> <code class="kt">double</code> <code class="n">progress</code> <code class="o">=</code> <code class="mf">0.44</code><code class="o">;</code> <code class="n">NumberFormat</code> <code class="n">pf</code> <code class="o">=</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getPercentInstance</code><code class="o">();</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="n">pf</code><code class="o">.</code><code class="na">format</code><code class="o">(</code><code class="n">progress</code><code class="o">)</code> <code class="o">);</code> <code class="c1">// "44%"</code> <code class="k">try</code> <code class="o">{</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="n">pf</code><code class="o">.</code><code class="na">parse</code><code class="o">(</code><code class="s">"77.2%"</code><code class="o">)</code> <code class="o">);</code> <code class="c1">// "0.772"</code> <code class="o">}</code> <code class="k">catch</code> <code class="o">(</code><code class="n">ParseException</code> <code class="n">e</code><code class="o">)</code> <code class="o">{}</code></pre><p>And if you just want to generate and parse plain old numbers, use a <code class="literal">NumberFormat</code> returned by <code class="literal">getInstance()</code> or its equivalent, <a id="I_indexterm10_id731350" class="indexterm"/><code class="literal">getNumberInstance()</code> :</p><a id="I_10_tt619"/><pre class="programlisting"> <code class="n">NumberFormat</code> <code class="n">guiseppe</code> <code class="o">=</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getInstance</code><code class="o">(</code><code class="n">Locale</code><code class="o">.</code><code class="na">ITALY</code><code class="o">);</code> <code class="c1">// defaults to Locale.US</code> <code class="n">NumberFormat</code> <code class="n">joe</code> <code class="o">=</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getInstance</code><code class="o">();</code> <code class="k">try</code> <code class="o">{</code> <code class="kt">double</code> <code class="n">theValue</code> <code class="o">=</code> <code class="n">guiseppe</code><code class="o">.</code><code class="na">parse</code><code class="o">(</code><code class="s">"34.663,252"</code><code class="o">).</code><code class="na">doubleValue</code><code class="o">();</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">joe</code><code class="o">.</code><code class="na">format</code><code class="o">(</code><code class="n">theValue</code><code class="o">));</code> <code class="c1">// "34,663.252"</code> <code class="o">}</code> <code class="k">catch</code> <code class="o">(</code><code class="n">ParseException</code> <code class="n">e</code><code class="o">)</code> <code class="o">{}</code></pre><p>We use <code class="literal">guiseppe</code> to parse a number in Italian format (periods separate thousands, comma is the decimal point). The return type of <code class="literal">parse()</code> is <code class="literal">Number</code>, so we use the <a id="I_indexterm10_id731391" class="indexterm"/><code class="literal">doubleValue()</code> method to retrieve the value of the <code class="literal">Number</code> as a <code class="literal">double</code>. Then we use <code class="literal">joe</code> to format the number correctly for the default (U.S.) locale.</p><p>Here’s a list of the factory methods for text formatters in the <code class="literal">java.text</code> package. Again, we’ll look at the <code class="literal">DateFormat</code> methods in the next chapter.</p><a id="I_10_tt620"/><pre class="programlisting"> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getCurrencyInstance</code><code class="o">()</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getCurrencyInstance</code><code class="o">(</code><code class="n">Locale</code> <code class="n">inLocale</code><code class="o">)</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getInstance</code><code class="o">()</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getInstance</code><code class="o">(</code><code class="n">Locale</code> <code class="n">inLocale</code><code class="o">)</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getNumberInstance</code><code class="o">()</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getNumberInstance</code><code class="o">(</code><code class="n">Locale</code> <code class="n">inLocale</code><code class="o">)</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getPercentInstance</code><code class="o">()</code> <code class="n">NumberFormat</code><code class="o">.</code><code class="na">getPercentInstance</code><code class="o">(</code><code class="n">Locale</code> <code class="n">inLocale</code><code class="o">)</code> <code class="n">DateFormat</code><code class="o">.</code><code class="na">getDateInstance</code><code class="o">()</code> <code class="n">DateFormat</code><code class="o">.</code><code class="na">getDateInstance</code><code class="o">(</code><code class="kt">int</code> <code class="n">style</code><code class="o">)</code> <code class="n">DateFormat</code><code class="o">.</code><code class="na">getDateInstance</code><code class="o">(</code><code class="kt">int</code> <code class="n">style</code><code class="o">,</code> <code class="n">Locale</code> <code class="n">aLocale</code><code class="o">)</code> <code class="n">DateFormat</code><code class="o">.</code><code class="na">getDateTimeInstance</code><code class="o">()</code> <code class="n">DateFormat</code><code class="o">.</code><code class="na">getDateTimeInstance</code><code class="o">(</code><code class="kt">int</code> <code class="n">dateStyle</code><code class="o">,</code> <code class="kt">int</code> <code class="n">timeStyle</code><code class="o">)</code> <code class="n">DateFormat</code><code class="o">.</code><code class="na">getDateTimeInstance</code><code class="o">(</code><code class="kt">int</code> <code class="n">dateStyle</code><code class="o">,</code> <code class="kt">int</code> <code class="n">timeStyle</code><code class="o">,</code> <code class="n">Locale</code> <code class="n">aLocale</code><code class="o">)</code> <code class="n">DateFormat</code><code class="o">.</code><code class="na">getInstance</code><code class="o">()</code> <code class="n">DateFormat</code><code class="o">.</code><code class="na">getTimeInstance</code><code class="o">()</code> <code class="n">DateFormat</code><code class="o">.</code><code class="na">getTimeInstance</code><code class="o">(</code><code class="kt">int</code> <code class="n">style</code><code class="o">)</code> <code class="n">DateFormat</code><code class="o">.</code><code class="na">getTimeInstance</code><code class="o">(</code><code class="kt">int</code> <code class="n">style</code><code class="o">,</code> <code class="n">Locale</code> <code class="n">aLocale</code><code class="o">)</code></pre><p>Thus far, we’ve seen how to format numbers as text. Now, we’ll take a look at a class, <a id="I_indexterm10_id731453" class="indexterm"/><code class="literal">ChoiceFormat</code>, that maps numerical ranges to text. <code class="literal">ChoiceFormat</code> is constructed by specifying the numerical ranges and the strings that correspond to them. One constructor accepts an array of <code class="literal">double</code>s and an array of <code class="literal">String</code>s, where each string corresponds to the range running from the matching number up to (but not including) the next number in the array:</p><a id="I_10_tt621"/><pre class="programlisting"> <code class="kt">double</code><code class="o">[]</code> <code class="n">limits</code> <code class="o">=</code> <code class="k">new</code> <code class="kt">double</code> <code class="o">[]</code> <code class="o">{</code><code class="mi">0</code><code class="o">,</code> <code class="mi">20</code><code class="o">,</code> <code class="mi">40</code><code class="o">};</code> <code class="n">String</code><code class="o">[]</code> <code class="n">labels</code> <code class="o">=</code> <code class="k">new</code> <code class="n">String</code> <code class="o">[]</code> <code class="o">{</code><code class="s">"young"</code><code class="o">,</code> <code class="s">"less young"</code><code class="o">,</code> <code class="s">"old"</code><code class="o">};</code> <code class="n">ChoiceFormat</code> <code class="n">cf</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ChoiceFormat</code><code class="o">(</code><code class="n">limits</code><code class="o">,</code> <code class="n">labels</code><code class="o">);</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">cf</code><code class="o">.</code><code class="na">format</code><code class="o">(</code><code class="mi">12</code><code class="o">));</code> <code class="c1">//"young"</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">cf</code><code class="o">.</code><code class="na">format</code><code class="o">(</code><code class="mi">26</code><code class="o">));</code> <code class="c1">// "less young"</code></pre><p>You can specify both the limits and the labels using a special string in an alternative <code class="literal">ChoiceFormat</code> constructor:</p><a id="I_10_tt622"/><pre class="programlisting"> <code class="n">ChoiceFormat</code> <code class="n">cf</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ChoiceFormat</code><code class="o">(</code><code class="s">"0#young|20#less young|40#old"</code><code class="o">);</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">cf</code><code class="o">.</code><code class="na">format</code><code class="o">(</code><code class="mi">40</code><code class="o">));</code> <code class="c1">// old</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">cf</code><code class="o">.</code><code class="na">format</code><code class="o">(</code><code class="mi">50</code><code class="o">));</code> <code class="c1">// old</code></pre><p>The limit and value pairs are separated by vertical bars (<code class="literal">|</code>); the number sign (<code class="literal">#</code>) separates each limit from its corresponding value.</p><p><code class="literal">ChoiceFormat</code> is most useful for handling pluralization in messages, enabling you to avoid hideous constructions such as, “you have one file(s) open.” You can create readable error messages by using <code class="literal">ChoiceFormat</code> along with the <code class="literal">MessageFormat</code> class.</p><div class="sect2" title="MessageFormat"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-10-SECT-6.1"/>MessageFormat</h2></div></div></div><p><a id="idx10532" class="indexterm"/> <code class="literal">MessageFormat</code> is a string formatter that uses a pattern string in the same way that <code class="literal">printf()</code> formatting does. <code class="literal">MessageFormat</code> has largely been replaced by <code class="literal">printf()</code>, which has more options and is more widely used outside of Java. Nonetheless, some may still prefer <code class="literal">MessageFormat</code>’s style, which is a bit less cryptic than that of <code class="literal">printf()</code>. <code class="literal">MessageFormat</code> has a static formatting method, <code class="literal">MessageFormat.format()</code>, paralleling the print-style formatting of <code class="literal">String.format()</code>.</p><p>Arguments in a <code class="literal">MessageFormat</code> format string are delineated by curly brackets and may include information about how they should be formatted. Each argument consists of a number, an optional type, and an optional style, as summarized in <a class="xref" href="ch10s06.html#learnjava3-CHP-10-TABLE-8" title="Table 10-8. MessageFormat arguments">Table 10-8</a>.</p><div class="table"><a id="learnjava3-CHP-10-TABLE-8"/><p class="title">Table 10-8. MessageFormat arguments</p><div class="table-contents"><table summary="MessageFormat arguments" style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; "><colgroup><col/><col/></colgroup><thead><tr><th style="text-align: left"><p>Type</p></th><th style="text-align: left"><p>Styles</p></th></tr></thead><tbody><tr><td style="text-align: left"><p> <a id="I_indexterm10_id731673" class="indexterm"/> <code class="literal">Choice</code> </p></td><td style="text-align: left"><p> <em class="replaceable"><code>pattern</code></em> </p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm10_id731699" class="indexterm"/> <code class="literal">Date</code> </p></td><td style="text-align: left"><p> <code class="literal">short</code>, <code class="literal">medium</code>, <code class="literal">long</code>, <code class="literal">full</code>, <em class="replaceable"><code>pattern</code></em></p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm10_id731745" class="indexterm"/> <code class="literal">Number</code> </p></td><td style="text-align: left"><p> <code class="literal">integer</code>, <code class="literal">percent</code>, <code class="literal">currency</code>, <em class="replaceable"><code>pattern</code></em></p></td></tr><tr><td style="text-align: left"><p> <a id="I_indexterm10_id731786" class="indexterm"/> <code class="literal">Time</code> </p></td><td style="text-align: left"><p> <code class="literal">short</code>, <code class="literal">medium</code>, <code class="literal">long</code>, <code class="literal">full</code>, <em class="replaceable"><code>pattern</code></em></p></td></tr></tbody></table></div></div><p>Let’s use an example to clarify this:</p><a id="I_10_tt623"/><pre class="programlisting"> <code class="c1">//Equivalent to String.format("You have %s messages.", "no");</code> <code class="n">MessageFormat</code><code class="o">.</code><code class="na">format</code><code class="o">(</code><code class="s">"You have {0} messages."</code><code class="o">,</code> <code class="s">"no"</code><code class="o">);</code></pre><p>The special incantation <code class="literal">{0}</code> means “use element zero of the arguments supplied to the <code class="literal">format()</code> method.” When we generate a message by calling <code class="literal">format()</code>, we pass in values to replace the placeholders (<code class="literal">{0}</code>, <code class="literal">{1}</code>, ... ) in the template. In this case, we pass the string “no” as <code class="literal">arguments[0]</code>, yielding the result, <code class="literal">You have no messages.</code></p><p>Let’s try this example again, but this time, we’ll format a number and a date instead of a string argument:</p><a id="I_10_tt624"/><pre class="programlisting"> <code class="n">MessageFormat</code> <code class="n">mf</code> <code class="o">=</code> <code class="k">new</code> <code class="n">MessageFormat</code><code class="o">(</code> <code class="s">"You have {0, number, integer} messages on {1, date, long}."</code><code class="o">);</code> <code class="c1">// "You have 93 messages on April 10, 2002."</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="n">mf</code><code class="o">.</code><code class="na">format</code><code class="o">(</code> <code class="mi">93</code><code class="o">,</code> <code class="k">new</code> <code class="n">Date</code><code class="o">()</code> <code class="o">)</code> <code class="o">);</code></pre><p>In this example, we need to fill in two spaces in the template, so we need two arguments. The first must be a number and is formatted as an integer. The second must be a <code class="literal">Date</code> and is printed in the <code class="literal">long</code> format.</p><p>This is still sloppy. What if there is only one message? To make this grammatically correct, we can embed a <code class="literal">ChoiceFormat</code>-style pattern string in our <code class="literal">MessageFormat</code> pattern string:</p><a id="I_10_tt625"/><pre class="programlisting"> <code class="n">MessageFormat</code> <code class="n">mf</code> <code class="o">=</code> <code class="k">new</code> <code class="n">MessageFormat</code><code class="o">(</code> <code class="s">"You have {0, number, integer} message{0, choice, 0#s|1#|2#s}."</code><code class="o">);</code> <code class="c1">// "You have 1 message."</code> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code> <code class="n">mf</code><code class="o">.</code><code class="na">format</code><code class="o">(</code> <code class="mi">1</code> <code class="o">)</code> <code class="o">);</code></pre><p>In this case, we use the first argument twice: once to supply the number of messages and once to provide input to the <code class="literal">ChoiceFormat</code> pattern. The pattern says to add an <code class="literal">s</code> if the argument has the value <code class="literal">0</code> or is <code class="literal">2</code> or more.</p><p>When writing internationalized programs, you can use resource bundles to supply not only the text of messages, but also the format strings for your <code class="literal">MessageFormat</code> objects. In this way, you can automatically format messages that are in the appropriate language with dates and other language-dependent fields handled appropriately and in the appropriate order. Because arguments in the format string are numbered, you can refer to them in any location. For example, in English, you might say, “Disk C has 123 files”; in some other language, you might say, “123 files are on Disk C.” You could implement both messages with the same set of arguments:</p><a id="I_10_tt626"/><pre class="programlisting"> <code class="n">MessageFormat</code> <code class="n">m1</code> <code class="o">=</code> <code class="k">new</code> <code class="n">MessageFormat</code><code class="o">(</code> <code class="s">"Disk {0} has {1, number, integer} files."</code><code class="o">);</code> <code class="n">MessageFormat</code> <code class="n">m2</code> <code class="o">=</code> <code class="k">new</code> <code class="n">MessageFormat</code><code class="o">(</code> <code class="s">"{1, number, integer} files are on disk {0}."</code><code class="o">);</code></pre><p>In real life, the code could be more compact; you’d use only a single <code class="literal">MessageFormat</code> object, initialized with a string taken from a resource bundle. Or you’d likely want to use the static <code class="literal">format</code> method or switch to <code class="literal">printf()</code> entirely.<a id="I_indexterm10_id732009" class="indexterm"/><a id="I_indexterm10_id732016" class="indexterm"/><a id="I_indexterm10_id732023" class="indexterm"/></p></div></div></body></html>