<?xml version="1.0" encoding="UTF-8"?> <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"> <colgroup width="87%"/> <colgroup width="13%"/> <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()) { 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 boolean equals</methodname>(<classname 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()) { System.out.println(values.pop(). 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" xml:id="sd1_numbers_fig_boxingAndUnboxing-3-co"/> 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" xml:id="sd1_numbers_fig_conventional-3-co"/> 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> using the class method <methodname 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> <figure xml:id="sd1_numbers_fig_stackBoxUnboxVsConventional"> <title>Boxing syntax comparison</title> <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()) { System.out.println(values.pop(). intValue()); }</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()) { System.out.println(values.pop()); }</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> <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"> <title>Parsing <classname 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; try (final Scanner scanner = new Scanner(System.in)){ System.out.print("Enter an integer:"); userInput = scanner.nextLine(); final int value = Integer.parseInt(userInput); 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 You entered -34</screen><screen>Enter an integer:five 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> method does not throw a <classname 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 initialized</code>.</para> <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 = Integer.parseInt("1101", 2); 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> 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> instance</title> <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> <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> documentation and its <methodname 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> providing the <methodname 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> and the <methodname xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/format/DateTimeFormatter.html#withLocale(java.util.Locale)">DateTimeFormatter 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); try { final Number[] values = { 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> <screen>103234(java.lang.Long) 400000.234(java.lang.Double) 103.234(java.lang.Double) 400(java.lang.Long)</screen> </figure> </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"); BigDecimal result = zero_dot_99. subtract(zero_dot_1). subtract(zero_dot_1). subtract(zero_dot_1); System.out.println(result);</programlisting> <screen>0.69</screen> </figure> <qandaset defaultlabel="qanda" xml:id="sd1_workingWithNumbers_BigDecimalChaining"> <title>Chaining subtract method calls</title> <qandadiv> <qandaentry> <question> <para>Explain the chaining mechanism implementing three successive subtractions in <xref linkend="sd1_numbers_fig_usingBigDecimalChaining"/>.</para> </question> <answer> <para>We may re-write the statement in question:</para> <programlisting language="none">result = zero_dot_99.subtract(zero_dot_1).subtract(zero_dot_1).subtract(zero_dot_1); \ / / / \ / / / \ / / / 0.99 - 0.1 / / \ / / \ / / \ / / 0.98 - 0.1 / \ / \ / 0.97 - 0.1 == 0.96</programlisting> <para>Each <methodname>subtract(...)</methodname> call returns a new result instance of class <classname xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html">BigDecimal</classname>. We can thus chain a subsequent <methodname>subtract(...)</methodname> call using this returned instance.</para> </answer> </qandaentry> </qandadiv> </qandaset> <figure xml:id="sd1_numbers_fig_usingBigDecimalFeatures"> <title><classname xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html">BigDecimal</classname> features</title> <itemizedlist> <listitem> <para>Higher memory allocation hosting higher precision.</para> </listitem> <listitem> <para>Immutable instances</para> </listitem> <listitem> <para>Calculation performance penalty.</para> </listitem> <listitem> <para>Clumsy interface.</para> </listitem> </itemizedlist> </figure> </section> <section xml:id="sd1_numbers_sect_GeneratingRandomNumbers"> <title>Generating Random Numbers</title> <figure xml:id="sd1_numbers_fig_random"> <title>Using <methodname xlink:href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Math.html#random()">static double random()</methodname></title> <programlisting language="java">for (int i = 0; i < 10; i++) { System.out.println(Math.random()); }</programlisting> <screen>0.4754286988826202 0.0060114391743414375 ... 0.9047785351372987 0.2516070321935864</screen> </figure> <figure xml:id="sd1_numbers_fig_randomSeed"> <title>Seeding a pseudo random generator</title> <programlisting language="java">try(final Scanner scanner = new Scanner(System.in)) { System.out.print("Enter an integer seed:"); final long seed = scanner.nextLong(); Random generator = new Random(seed); for (int i = 0; i < 10; i++) { System.out.print(generator.nextBoolean() + " "); } }</programlisting> <screen>Enter an integer seed:4237549835735 false true true true false false false true false true</screen> </figure> </section> </chapter>