Newer
Older
<chapter annotations="slide" version="5.1"
xml:id="sd1_workingWithNumbers_chap"
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xila="http://www.w3.org/2001/XInclude/local-attributes"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:ns="http://docbook.org/ns/transclusion"
xmlns:m="http://www.w3.org/1998/Math/MathML"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:db="http://docbook.org/ns/docbook">
<title>Working with Numbers</title>
<section xml:id="sd1_numbers_sect_boxAndUnbox">
<title>Boxing and Unboxing</title>
<figure xml:id="sd1_numbers_fig_stack">
<title><classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Stack.html">Stack</classname>
of integer values</title>
<informaltable border="0">
<td valign="top"><programlisting language="java">final Stack<Integer> values = new Stack<>();
values.push(3);
values.push(1);
values.push(10);
while (!values.empty()) {
final int i = values.pop();
System.out.println(i);
}</programlisting></td>
<td valign="top"><screen>10
1
3</screen></td>
</tr>
</informaltable>
</figure>
<figure xml:id="sd1_numbers_fig_collectionProperties">
<title><xref linkend="glo_Java"/> collection features</title>
<itemizedlist>
<listitem>
<para>Supports searching of objects based on:</para>
<itemizedlist>
<listitem>
<para><methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html#equals(java.lang.Object)">public
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html">Object</classname>
obj)</para>
</listitem>
<listitem>
<para><methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html#hashCode()">public
int hashCode()</methodname></para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>Objects only, no primitive types!</para>
</listitem>
</itemizedlist>
</figure>
<figure xml:id="sd1_numbers_fig_stackBehindTheScenes">
<title>Behind the scenes</title>
<informaltable border="0">
<colgroup width="48%"/>
<colgroup width="50%"/>
<tr>
<td valign="top"><programlisting language="java">final Stack<Integer> values =
new Stack<>();
values.push(3);
values.push(1);
values.push(10);
while (!values.empty()) {
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
getClass().getTypeName());
}</programlisting></td>
<td valign="top"><screen>java.lang.Integer
java.lang.Integer
java.lang.Integer</screen></td>
</tr>
</informaltable>
</figure>
<figure xml:id="sd1_numbers_fig_boxingAndUnboxing">
<title><link
xlink:href="https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html">Boxing
and unboxing</link></title>
<informaltable border="0">
<colgroup width="50%"/>
<colgroup width="50%"/>
<tr>
<td valign="top"><programlisting language="none">int iPrimitive <co
linkends="sd1_numbers_fig_boxingAndUnboxing-1"
xml:id="sd1_numbers_fig_boxingAndUnboxing-1-co"/> = 7;
Integer iInteger = <co linkends="sd1_numbers_fig_boxingAndUnboxing-2"
xml:id="sd1_numbers_fig_boxingAndUnboxing-2-co"/>
iPrimitive;
int iPrimitiveFromInteger = <co linkends="sd1_numbers_fig_boxingAndUnboxing-3"
iInteger;</programlisting></td>
<td valign="top"><programlisting language="none">int iPrimitive <co
linkends="sd1_numbers_fig_conventional-1"
xml:id="sd1_numbers_fig_conventional-1-co"/> = 7;
Integer iInteger = <co linkends="sd1_numbers_fig_conventional-2"
xml:id="sd1_numbers_fig_conventional-2-co"/>
Integer.valueOf(iPrimitive);
int iPrimitiveFromInteger = <co linkends="sd1_numbers_fig_conventional-3"
iInteger.intValue();</programlisting></td>
</tr>
</informaltable>
<informaltable border="1" role="slideExclude">
<colgroup width="50%"/>
<colgroup width="50%"/>
<tr>
<th>Boxing and unboxing</th>
<th><quote>Conventional</quote> <xref linkend="glo_Java"/></th>
</tr>
<tr>
<td valign="top"><calloutlist>
<callout arearefs="sd1_numbers_fig_boxingAndUnboxing-1-co"
xml:id="sd1_numbers_fig_boxingAndUnboxing-1">
<para>Defining a primitive <code language="java">int</code>
value.</para>
</callout>
<callout arearefs="sd1_numbers_fig_boxingAndUnboxing-2-co"
xml:id="sd1_numbers_fig_boxingAndUnboxing-2">
<para>Creating an instance of <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Integer.html">Integer</classname>
by means of boxing.</para>
</callout>
<callout arearefs="sd1_numbers_fig_boxingAndUnboxing-3-co"
xml:id="sd1_numbers_fig_boxingAndUnboxing-3">
<para>Assigning an <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Integer.html">Integer</classname>'s
value to a primitive <code language="java">int</code> by means
of unboxing.</para>
</callout>
</calloutlist></td>
<td valign="top"><calloutlist>
<callout arearefs="sd1_numbers_fig_conventional-1-co"
xml:id="sd1_numbers_fig_conventional-1">
<para>Defining a primitive <code language="java">int</code>
value.</para>
</callout>
<callout arearefs="sd1_numbers_fig_conventional-2-co"
xml:id="sd1_numbers_fig_conventional-2">
<para>Creating a new instance of <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Integer.html">Integer</classname>
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Integer.html#valueOf(int)">Integer
valueOf(int i)</methodname>.</para>
</callout>
<callout arearefs="sd1_numbers_fig_conventional-3-co"
xml:id="sd1_numbers_fig_conventional-3">
<para>Assigning an <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Integer.html">Integer</classname>'s
value to a primitive <code language="java">int</code> using
the <methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Integer.html#intValue()">int
intValue()</methodname> instance method.</para>
</callout>
</calloutlist></td>
</tr>
</informaltable>
<figure xml:id="sd1_numbers_fig_stackBoxUnboxVsConventional">
<informaltable border="0">
<colgroup width="50%"/>
<colgroup width="50%"/>
<tr>
<td valign="top"><programlisting language="java">final Stack<Integer> values
= new Stack<>();
values.push(Integer.valueOf(3));
values.push(Integer.valueOf(1));
values.push(Integer.valueOf(10));
while (!values.empty()) {
}</programlisting></td>
<td valign="top"><programlisting language="java">final Stack<Integer> values =
new Stack<>();
values.push(3);
values.push(1);
values.push(10);
while (!values.empty()) {
}</programlisting></td>
</tr>
</informaltable>
</figure>
<qandaset defaultlabel="qanda"
xml:id="sd1_numbers_qanda_boxing_int2Double">
<title>Auto boxing int to Double?</title>
<qandadiv>
<qandaentry>
<question>
<para>Consider the following two code snippets:</para>
<informaltable border="0">
<tr>
<td valign="top"><programlisting language="java">Double d = 3.0;</programlisting></td>
<td valign="top"><programlisting language="java">Double d = 3;</programlisting></td>
</tr>
<tr>
<td valign="top">o.K.</td>
<td valign="top"><para>Compile time error:</para><screen>Incompatible types.
Required: java.lang.Double
Found: int</screen></td>
</tr>
</informaltable>
<para>Explain this result. Hint: You may want to read <link
xlink:href="https://docs.oracle.com/javase/specs/jls/se12/html/jls-5.html">chapter
5</link> and <link
xlink:href="https://docs.oracle.com/javase/specs/jls/se12/html/jls-5.html#jls-5.2">section
5.2</link> in particular from the <link
xlink:href="https://docs.oracle.com/javase/specs/jls/se12/html/">The
Java® Language Specification</link>.</para>
</question>
<answer>
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
<para><quote>3.0</quote> is a double literal. For the sake of
clarification we may rewrite the working code snippet:</para>
<programlisting language="java">double doubleValue = 3.0;
Double d = doubleValue;</programlisting>
<para>With autoboxing on offer the compiler will silently box the
value of type <code language="java">double</code> into a
corresponding instance of type
<classname>Double</classname>.</para>
<para>On contrary <quote>3</quote> is an <code
language="java">int</code> literal allowing for re-writing the
second snippet as:</para>
<programlisting language="java">int intValue = 3.0;
Double d = intValue;</programlisting>
<para>The <quote
xlink:href="https://docs.oracle.com/javase/specs/jls/se12/html/jls-5.html#jls-5.1.7">Boxing
Conversion</quote> section does not define an <code
language="java">int</code> to <classname>Double</classname> boxing
conversion: The compiler will thus not perform auto boxing from
<code>int</code> do <classname>Double</classname>.</para>
<para>An <code language="java">int</code> could however be
auto-boxed into an <classname>Integer</classname>. But
<classname>Double</classname> not being a subtype of
<classname>Integer</classname> disallows a widening reference
conversion.</para>
</answer>
</qandaentry>
</qandadiv>
</qandaset>
</section>
<section xml:id="sd1_numbers_sect_numberParsing">
<title>Number Parsing</title>
<figure xml:id="sd1_numbers_fig_parseIntegerString">
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Integer.html">Integer</classname>
user input</title>
<informaltable border="0">
<colgroup width="65%"/>
<colgroup width="35%"/>
<tr>
<td valign="top"><programlisting language="java">String userInput = null;
System.out.print("Enter an integer:");
userInput = scanner.nextLine();
System.out.println("You entered " + value);
} catch (final NumberFormatException e) {
System.out.println("Error: No integer value");
}</programlisting></td>
<td valign="top"><screen>Enter an integer:-34
Sorry, but 'five' is
not an integer.</screen></td>
</tr>
</informaltable>
</figure>
<qandaset defaultlabel="qanda" xml:id="sd1_numbers_qanda_whyDummyString">
<title>Why using <code language="java">String userInput =
null</code>?</title>
<qandadiv>
<qandaentry>
<question>
<para>The former listing initializes the <code
language="java">userInput</code> variable using a default value
<code language="java">null</code>. Why is that?</para>
<orderedlist>
<listitem>
<para>The variable <code language="java">userInput</code> is
being assigned inside the <code language="java">try
{...}</code> block before being used in any assignment.</para>
</listitem>
<listitem>
<para>The <methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Scanner.html#nextLine()">Scanner.nextLine()</methodname>
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/NumberFormatException.html">NumberFormatException</classname>.
Thus the only way to enter the <code language="java">catch
{...}</code> clause is by executing of <code
language="java">Integer.parseInt(userInput)</code> yielding a
<classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/NumberFormatException.html">NumberFormatException</classname>
. But this execution happens <emphasis>after</emphasis>
assigning <code language="java">userInput =
scanner.nextLine()</code>.</para>
</listitem>
</orderedlist>
<para>So the dummy assignment <code language="java">String
userInput = null</code> seems to be redundant. Is that
true?</para>
</question>
<answer>
<para>Actually the <xref linkend="glo_Java"/> compiler is not
clever enough analyzing the <code language="java">try {...}</code>
block. The catch clause can only be reached by inadequate user
input causing the <methodname>parseInt(...)</methodname> method.
In particular the <methodname>nextLine(...)</methodname> being
unable to throw a <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/NumberFormatException.html">NumberFormatException</classname>
cannot be the culprit for entering the <code
language="java">catch</code> clause. Thus if a <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/NumberFormatException.html">NumberFormatException</classname>
is being thrown our <code language="java">userInput</code>
variable will already carry a user entered input string. The
compiler however cannot analyze this type of dependency.</para>
<para>Thus the possibility of an uninitialized <code
language="java">userInput</code> variable using just <code
language="java">String userInput;</code> would cause a compile
time error <code>Variable 'userInput' might not have been
<para><code language="java">So userInput = null</code> is
sufficient for keeping the compiler happy and inside the catch
clause the variable will definitively carry a<classname>
String</classname> reference.</para>
</answer>
</qandaentry>
</qandadiv>
</qandaset>
<figure xml:id="sd1_numbers_fig_parseIntegerToRadix">
<title>Parsing binary representation</title>
<informaltable border="0">
<colgroup width="50%"/>
<colgroup width="50%"/>
<tr>
<td valign="top"><programlisting language="java">final int value =
System.out.println("Value: " + value);</programlisting><screen>Value: 13</screen></td>
<td valign="top"><programlisting language="java">final int value =
Integer.parseInt("201", 2);
System.out.println("Value: " + value)</programlisting><screen>Exception in thread "main"
java.lang.NumberFormatException:
For input string: "201"
...
at de.hdm_stuttgart.sd1...</screen></td>
</tr>
</informaltable>
</figure>
<figure xml:id="sd1_numbers_fig_parseMethods">
<title>Standard parse methods</title>
<informaltable border="0">
<colgroup width="50%"/>
<colgroup width="50%"/>
<tr>
<td valign="top"><itemizedlist>
<listitem>
<para><methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Byte.html#parseByte(java.lang.String)">parseByte()</methodname></para>
</listitem>
<listitem>
<para><methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Short.html#parseShort(java.lang.String)">parseShort()</methodname></para>
</listitem>
<listitem>
<para><methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Integer.html#parseInt(java.lang.String)">parseInt()</methodname></para>
</listitem>
<listitem>
<para><methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Long.html#parseLong(java.lang.String)">parseLong()</methodname></para>
</listitem>
</itemizedlist></td>
<td valign="top"><itemizedlist>
<listitem>
<para><methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Float.html#parseFloat(java.lang.String)">parseFloat()</methodname></para>
</listitem>
<listitem>
<para><methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Double.html#parseDouble(java.lang.String)">parseDouble()</methodname></para>
</listitem>
<listitem>
<para><methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Boolean.html#parseBoolean(java.lang.String)">parseBoolean()</methodname></para>
</listitem>
</itemizedlist></td>
</tr>
</informaltable>
</figure>
<qandaset defaultlabel="qanda" xml:id="sd1_numbers_qanda_parseShortResult">
<title>Parsing <code language="java">short</code> values</title>
<qandadiv>
<qandaentry>
<question>
<para>Which outcome do you expect? Try to answer without prior
execution.</para>
<programlisting language="java">System.out.println(Short.parseShort("32767"));
System.out.println(Short.parseShort("32768"));</programlisting>
<para>Explain the result.</para>
</question>
<answer>
<para><code language="java"
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Short.html#MAX_VALUE">MAX_VALUE</code>
for primitive type <code language="java"
xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-B">short</code>
is <inlineequation>
<m:math display="inline">
<m:mrow>
<m:msup>
<m:mi>2</m:mi>
<m:mrow>
<m:mi>16</m:mi>
<m:mo>-</m:mo>
<m:mi>1</m:mi>
</m:mrow>
</m:msup>
<m:mo>-</m:mo>
<m:mi>1</m:mi>
</m:mrow>
</m:math>
</inlineequation> which equals 32767. Thus 32786 is no longer
assignment compatible. So the first line will execute well but the
second one yields a <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/NumberFormatException.html">NumberFormatException</classname>
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
at runtime :</para>
<screen>Value:32767
Exception in thread "main" java.lang.NumberFormatException:
Value out of range. Value:"32768" Radix:10 at
java.lang.Short.parseShort(Short.java:120)
at java.lang.Short.parseShort(Short.java:144)
at de.hdm_stuttgart.sd1.ParseShortTooBig.main(ParseShortTooBig.java:8)</screen>
</answer>
</qandaentry>
</qandadiv>
</qandaset>
<qandaset defaultlabel="qanda" xml:id="sd1_numbers_qanda_parseHexadecimal">
<title>Parsing <code language="java">short</code> values in hexadecimal
representation</title>
<qandadiv>
<qandaentry>
<question>
<para>An image processing application yields the following type of
data:</para>
<programlisting language="java">String[] values = {"C9", "AF3", "B"}; // Hexadecimal string values</programlisting>
<para>We are looking for a class method parsing these hex values
and converting them to <code language="java">short</code>:</para>
<programlisting language="java">/**
* Convert a numerical value given as hexadecimal string to
* its counterpart of type short. Example:
*
* "2B" equals 2 * 16 + 11 == 43
*
* @param input String containing hexadecimal value.
* @return the parsed short value.
*/
public static short getHexadecimal(final String input) {
...
return ...;
}</programlisting>
<para>The provided sample data may then be processed like:</para>
<programlisting language="java">final String[] values = {"C9", "AF3", "B"};
for (final String value: values) {
System.out.println(value + ": " + getHexadecimal(value));
}</programlisting>
<para>Result:</para>
<screen>C9: 201
AF3: 2803
B: 11</screen>
<tip>
<para>Have a look to the binary parse example and think about
representations.</para>
</tip>
</question>
<answer>
<para>Hexadecimal representation uses a radix value of 16 to be
passed to <methodname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Short.html#parseShort(java.lang.String,int)">short
parseShort(String s, int radix)</methodname>:</para>
<programlisting language="java">/**
* Convert a numerical value given as hexadecimal string to
* its counterpart of type short. Example:
*
* "2B" equals 2 * 16 + 11 == 43
*
* @param input String containing hexadecimal value.
* @return the parsed short value.
*/
public static short getHexadecimal(final String input) {
return Short.parseShort(input, 16);
}</programlisting>
</answer>
<answer>
<para><code language="java"
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Short.html#MAX_VALUE">MAX_VALUE</code>
for primitive type <code language="java"
xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-B">short</code>
is <inlineequation>
<m:math display="inline">
<m:mrow>
<m:msup>
<m:mi>2</m:mi>
<m:mrow>
<m:mi>16</m:mi>
<m:mo>-</m:mo>
<m:mi>1</m:mi>
</m:mrow>
</m:msup>
<m:mo>-</m:mo>
<m:mi>1</m:mi>
</m:mrow>
</m:math>
</inlineequation> which equals 32767. Thus 32786 is no longer
assignment compatible. So the first line will execute well but the
second one yields a <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/NumberFormatException.html">NumberFormatException</classname>
at runtime :</para>
<screen>Value:32767
Exception in thread "main" java.lang.NumberFormatException:
Value out of range. Value:"32768" Radix:10 at
java.lang.Short.parseShort(Short.java:120)
at java.lang.Short.parseShort(Short.java:144)
at de.hdm_stuttgart.sd1.ParseShortTooBig.main(ParseShortTooBig.java:8)</screen>
</answer>
</qandaentry>
</qandadiv>
</qandaset>
</section>
<section xml:id="sd1_numbers_sect_NumberFormatting">
<title>Number Formatting</title>
<figure xml:id="sd1_numbers_fig_locale">
<title>Excerpt from <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html">java.util.Locale</classname></title>
<para>A Locale object represents a specific geographical, political, or
cultural region.</para>
<para>An operation that requires a Locale to perform its task is called
locale-sensitive and uses the Locale to tailor information for the
user.</para>
<para>For example, displaying a number is a locale-sensitive operation:
Numbers should be formatted according to the customs and conventions of
the user's native country, region, or culture.</para>
</figure>
<figure xml:id="sd1_numbers_fig_localeProperties">
<title><classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html">Locale</classname>
properties</title>
<itemizedlist>
<listitem>
<para>Language</para>
</listitem>
<listitem>
<para>Encoding</para>
</listitem>
<listitem>
<para>Country</para>
</listitem>
<listitem>
<para>Extensible</para>
</listitem>
</itemizedlist>
</figure>
<figure xml:id="sd1_numbers_fig_constructNumberFormat">
<title>Get a <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/text/NumberFormat.html">NumberFormat</classname>
<informaltable border="0">
<tr>
<td valign="top"><programlisting language="none">final NumberFormat standard = new DecimalFormat();
System.out.println(standard.format(<emphasis role="red">1234.5678</emphasis>));
final NumberFormat de =
DecimalFormat.getInstance(Locale.GERMANY);
System.out.println(de.format(<emphasis role="red">1234.5678</emphasis>));</programlisting></td>
<td valign="top"><screen><emphasis role="red">1234.5678</emphasis>
<emphasis role="red">1.234,568</emphasis></screen></td>
</tr>
</informaltable>
</figure>
<figure xml:id="sd1_numbers_fig_customFormat">
<title>Create a custom formatter</title>
<programlisting language="java">final DecimalFormatSymbols unusualSymbols =
new DecimalFormatSymbols(Locale.getDefault());
unusualSymbols.setDecimalSeparator(<emphasis role="red">'|'</emphasis>);
unusualSymbols.setGroupingSeparator(<emphasis role="red">'^'</emphasis>);
final String strange = "#,##0.###";
final DecimalFormat weirdFormatter = new DecimalFormat(strange, unusualSymbols);
weirdFormatter.setGroupingSize(4);
System.out.println(weirdFormatter.format(12345.678));</programlisting>
<screen>1<emphasis role="red">^</emphasis>2345<emphasis role="red">|</emphasis>678</screen>
</figure>
<qandaset defaultlabel="qanda"
xml:id="sd1_numbers_qanda_getAvailableLocales">
<title><classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html">Locale</classname>
definitions</title>
<qandadiv>
<qandaentry>
<question>
<para>Each <xref linkend="glo_JRE"/> ships with a set of available
<classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html">Locale</classname>
definitions. Write a simple program to get the following
list:</para>
<screen>160 locales available:
Locale: Arabic(ar_AE)
Locale: Arabic(ar_JO)
Locale: Arabic(ar_SY)
Locale: Croatian(hr_HR)
...
Locale: Indonesian(in_ID)
Locale: English(en_GB)</screen>
<tip>
<para>Read the documentation of <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Locale.html">Locale</classname>
to find appropriate methods.</para>
</tip>
</question>
<answer>
<programlisting language="java">System.out.println(Locale.getAvailableLocales().length + " locales available:");
for (final Locale l: Locale.getAvailableLocales()) {
System.out.println("Locale: " + l.getDisplayLanguage() + "(" + l + ")");
}</programlisting>
</answer>
</qandaentry>
</qandadiv>
</qandaset>
<qandaset defaultlabel="qanda"
xml:id="sd1_numbers_qanda_formatIntDoubleDate">
<title>Formatting <code language="java">int</code>, <code
language="java">double</code> and <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/LocalDate.html">LocaleDate</classname></title>
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
<qandadiv>
<qandaentry>
<question>
<para>Implement the following three overloaded class
methods:</para>
<programlisting language="java">/**
* Print an int value using the given locale. Example:
*
* Using Locale.GERMANY a value of 1234567 should appear as "1.234.567"
*
* @param value The value to be formatted.
* @param locale The locale to be used.
*/
static public void print(final int value, final Locale locale) {...}</programlisting>
<programlisting language="java">/**
* Print a double value using the given locale. Example:
*
* Using Locale.GERMANY a value of -123.456789 should appear as "-123,457"
*
* @param value The value to be formatted.
* @param locale The locale to be used.
*/
static public void print(final double value, final Locale locale) {...}</programlisting>
<programlisting language="java">/**
* Print a {@link LocalDate} value using the given locale. Example:
*
* Using Locale.GERMANY the 22-nd of december 2024 should appear as "22. Dezember 2024".
*
* @param value The value to be formatted.
* @param locale The locale to be used.
*/
static public void print(final LocalDate date, final Locale locale) {...}</programlisting>
<para>You may use them as:</para>
<programlisting language="java">for (final Locale locale : new Locale[]{Locale.GERMANY, Locale.JAPAN, Locale.US}) {
System.out.println("Locale " + locale.getDisplayCountry());
print(1234567, locale);
print(-123.456789, locale);
print(LocalDate.of(2024, Month.DECEMBER, 22), locale);
System.out.println("----------------------\n");
}</programlisting>
<para>The expected output reads:</para>
<screen>Locale Germany
1.234.567
-123,457
22. Dezember 2024
----------------------
Locale Japan
1,234,567
-123.457
2024/12/22
----------------------
Locale United States
1,234,567
-123.457
December 22, 2024
----------------------</screen>
<tip>
<itemizedlist>
<listitem>
<para>Read the <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/text/NumberFormat.html">NumberFormat</classname>
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/text/NumberFormat.html#getInstance(java.util.Locale)">static
NumberFormat getInstance(Locale inLocale)</methodname> in
particular. Also note its multiply overloaded
<methodname>String format(...)</methodname> methods partly
suiting your data type requirements.</para>
</listitem>
<listitem>
<para>Regarding dates you may want to consider <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/format/DateTimeFormatter.html">DateTimeFormatter</classname>
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/format/DateTimeFormatter.html#ofLocalizedDate(java.time.format.FormatStyle)">static
DateTimeFormatter ofLocalizedDate(FormatStyle
dateStyle)</methodname> method. Then read about class
<classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/format/FormatStyle.html">FormatStyle</classname>
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/format/DateTimeFormatter.html#withLocale(java.util.Locale)">DateTimeFormatter
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
withLocale(Locale locale)</methodname> method.</para>
</listitem>
</itemizedlist>
</tip>
</question>
<answer>
<para>Implementing the first two methods is relatively
simple:</para>
<programlisting language="java">/**
* Print an int value using the given locale. Example:
*
* Using Locale.GERMANY a value of 1234567 should appear as "1.234.567"
*
* @param value The value to be formatted.
* @param locale The locale to be used.
*/
static public void print(final int value, final Locale locale) {
final NumberFormat numberFormat = NumberFormat.getInstance(locale);
System.out.println(numberFormat.format(value));
}</programlisting>
<programlisting language="java">/**
* Print a double value using the given locale. Example:
*
* Using Locale.GERMANY a value of -123.456789 should appear as "-123,457"
*
* @param value The value to be formatted.
* @param locale The locale to be used.
*/
static public void print(final double value, final Locale locale) {
final NumberFormat numberFormat = NumberFormat.getInstance(locale);
System.out.println(numberFormat.format(value));
}</programlisting>
<para>Processing dates is a bit cumbersome:</para>
<programlisting language="java">/**
* Print a {@link LocalDate} value using the given locale. Example:
*
* Using Locale.GERMANY the 22-nd of december 2024 should appear as "22. Dezember 2024".
*
* @param value The value to be formatted.
* @param locale The locale to be used.
*/
static public void print(final LocalDate date, final Locale locale) {
final DateTimeFormatter dateFormat =
DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withLocale(locale);
System.out.println(dateFormat.format(date));
}</programlisting>
</answer>
</qandaentry>
</qandadiv>
</qandaset>
<figure xml:id="sd1_numbers_fig_polymorphicNumberParsing">
<title>Polymorphic number parsing</title>
<programlisting language="java">final NumberFormat de = NumberFormat.getInstance(Locale.GERMANY),
us = NumberFormat.getInstance(Locale.US);
de.parse("103.234"), de.parse("400.000,234"),
us.parse("103.234"), us.parse("400.000,234"),};
for (final Number n: values) {
System.out.println(n + "(" + n.getClass().getTypeName() + ")");
} catch (ParseException e) { ... }</programlisting>
400000.234(java.lang.Double)
103.234(java.lang.Double)
400(java.lang.Long)</screen>
</section>
<section xml:id="sd1_numbers_sect_WorkingwithMoney">
<title>Working with Money</title>
<figure xml:id="sd1_numbers_fig_floatLimitedPreceision">
<title>Limited <code language="java">float</code> precision</title>
<programlisting language="java">final float result = 0.99f - 0.1f -0.1f -0.1f;
System.out.println(result);</programlisting>
<screen>0.68999994</screen>
</figure>
<figure xml:id="sd1_numbers_fig_doubleLimitedPreceision">
<title>Limited <code language="java">double</code> precision</title>
<programlisting language="java">final double result = 0.99 - 0.1 -0.1 -0.1;
System.out.println(result);</programlisting>
<screen>0.6900000000000001</screen>
</figure>
<figure xml:id="sd1_numbers_fig_usingBigDecimal">
<title>Using <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html">BigDecimal</classname></title>
<programlisting language="java">final BigDecimal zero_dot_99 = new BigDecimal("0.99");
final BigDecimal zero_dot_1 = new BigDecimal("0.1");
BigDecimal
result = zero_dot_99.subtract(zero_dot_1); // Subtracting 0.1
result = result.subtract(zero_dot_1); // Subtracting 0.1
result = result.subtract(zero_dot_1); // Subtracting 0.1
System.out.println(result);</programlisting>
<screen>0.69</screen>
</figure>
<figure xml:id="sd1_numbers_fig_usingBigDecimalChaining">
<title>Chaining <classname
xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html">BigDecimal</classname>
operations</title>
<programlisting language="java">final BigDecimal zero_dot_99 = new BigDecimal("0.99");
final BigDecimal zero_dot_1 = new BigDecimal("0.1");