<?xml version="1.0" encoding="UTF-8"?> <section version="5.0" xml:id="sd1_exam_2021_winter" xml:lang="en" 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:trans="http://docbook.org/ns/transclusion" xmlns:svg="http://www.w3.org/2000/svg" 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>SD1 examination winter 2021</title> <section xml:id="sd1_exam_2021_winter_task1"> <title>Implementing tasks</title> <section xml:id="sd1_exam_2021_winter_task1_preparation"> <title>Preparation</title> <orderedlist> <listitem> <para>Download and unzip the above file <filename>exam.zip</filename>. You should see a directory »<filename>Exam</filename>« containing a <filename>pom.xml</filename> file.</para> </listitem> <listitem> <para>Open this project in your <productname>IDEA</productname> IDE by selecting the <filename>Exam/pom.xml</filename> file.</para> </listitem> </orderedlist> </section> <section xml:id="sd1_exam_2021_winter_task1_tasks"> <title>Tasks</title> <qandaset defaultlabel="qanda" xml:id="sd1_exam_2021_winter_task1Qanda"> <qandadiv> <qandaentry> <question> <para>Open the <filename>Readme.md</filename> file in your project's root. It contains all necessary instructions for solving the implementation tasks.</para> </question> <answer> <para>Solution see <link xlink:href="https://gitlab.mi.hdm-stuttgart.de/goik/GoikLectures/-/tree/master/Klausuren/Sd1/2021winter/Solve">winter 2021 Exam</link>.</para> </answer> </qandaentry> </qandadiv> </qandaset> </section> <section xml:id="sd1_exam_2021_winter_examCaveats"> <title>Caveats</title> <itemizedlist> <listitem> <para>When approaching end of examination check your input for completeness prior to being automatically logged out by the system. Remember: There is 120 minutes for the examination and another 5 minutes to check for completeness.</para> </listitem> <listitem> <para>Projects residing just on your local workstation's file system cannot be recovered after finishing the exam.</para> </listitem> </itemizedlist> </section> </section> <section xml:id="sd1_exam_2021_winter_task2"> <title><methodname>equals()</methodname> and <methodname>hashCode()</methodname></title> <qandaset defaultlabel="qanda" xml:id="sd1_exam_2021_winter_task2Qanda"> <qandadiv> <qandaentry> <question> <para>Consider the following <classname>Person</classname> class:</para> <programlisting language="java">public class Person { private String name, // Guaranteed never comment; // to be null private int ageInYears; // Other methods omitted for brevity @Override public boolean equals(Object o) { if (o instanceof Person) { final Person p = (Person) o; return ageInYears == p.ageInYears && name.equals(p.name); } else { return false; } } @Override public int hashCode() { return ageInYears + 13 * comment.hashCode(); } }</programlisting> <para>We assume the above <methodname>equals()</methodname> implementation to be correct. Answer the following two questions:</para> <orderedlist> <listitem> <para>Is this implementation correct regarding the <link xlink:href="https://freedocs.mi.hdm-stuttgart.de/doc/openjdk-21-doc/api/java.base/java/lang/Object.html#hashCode()">contract between <methodname>equals()</methodname> and <methodname>hashCode()</methodname></link>? Correct if necessary.</para> </listitem> <listitem> <para>After correcting possible flaws: Is the resulting implementation »good« with respect to distinguishing objects? Amend if possible.</para> </listitem> </orderedlist> <para>Explain your answers.</para> </question> <answer> <orderedlist> <listitem> <para>The <methodname>equals(...)</methodname> method defines two <classname>Person</classname> instances to be equal when having common age and Name. Thus two instances e.g. <code>(18, "Eve Porter", "New Friend from holiday")</code> and <code>(18, "Eve Porter", "Friendly person")</code>of common name and age but having a different comment will still considered to be equal.</para> <para>Since equality is being defined solely on <property>age</property> and <property>name</property> the <property>comment</property> attribute must not be used for implementing <methodname>hashCode()</methodname>. Otherwise the above example will result in different hash values contradicting the <methodname>equals(...)</methodname> / <methodname>hashCode()</methodname> contract. We thus have:</para> <programlisting language="java">public class Person { ... @Override public int hashCode() { return ageInYears; } }</programlisting> </listitem> <listitem> <para>The previously corrected <methodname>hashCode()</methodname> implementation is correct with respect to its related <methodname>equals()</methodname> method. However all <classname>Person</classname> instances of common <property>age</property> but different <property>name</property> will be defined to be different by our <methodname>equals(...)</methodname> method. But they will all share the same <methodname>hashCode()</methodname> value throughout. So our <methodname>hashCode()</methodname> method is not particularly good when it comes to distinguish objects. Adding the <property>name</property> property to our <methodname>hashCode()</methodname> calculation solves this issue:</para> <programlisting language="java">public class Person { ... @Override public int hashCode() { return ageInYears + 13 * name.hashCode(); } }</programlisting> </listitem> </orderedlist> </answer> </qandaentry> </qandadiv> </qandaset> </section> <section xml:id="sd1_exam_2021_winter_task3"> <title>The average of three byte values</title> <qandaset defaultlabel="qanda" xml:id="sd1_exam_2021_winter_task3Qanda"> <qandadiv> <qandaentry> <question> <para>A newbie programmer codes the following snippet:</para> <programlisting language="java">/** * The average of three values * * @param a First value * @param b Second value * @param c Third value * * @return Closest <code>byte</code> value to ⅓ (a + b + c) */ public static byte getAverage(byte a, final byte b, final byte c) { a += b; a += c; a /= 3; return a; }</programlisting> <para>A senior programming companion warns about two possible problems:</para> <orderedlist> <listitem> <para>The implementation is prone to overflow errors.</para> </listitem> <listitem> <para>The implementation will in many cases return unnecessarily inaccurate results.</para> </listitem> </orderedlist> <para>Explain both points in the answer box below.</para> <para>In addition provide a solution by modifying the above implementation without changing the method's signature. You may present your code in the answer box below as well.</para> <para>Alternatively correct the implementation of <package>de.hdm_stuttgart.mi.sd1.task4_no_unit_test</package>.<classname>Mathextend</classname> within your downloaded and imported <filename>exam.zip</filename> project using your IDEA IDE. In this case <emphasis role="red">Do not forget to export and upload after finishing by using task 1 of this examination</emphasis>.</para> <tip> <para><methodname xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Math.html#round(double)">Math.round(double)</methodname> might be your friend.</para> </tip> </question> <answer> <orderedlist> <listitem> <para>Biggest problem here: The operator <code language="java">+=</code>'s way of cycling through a <code language="java">byte</code>'s range when exceeding <code language="java" xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Byte.html#MAX_VALUE">Byte.MAX_VALUE</code> or <code language="java" xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Byte.html#MIN_VALUE">Byte.MIN_VALUE</code> boundaries. Consider:</para> <informaltable border="1"> <colgroup width="76%"/> <colgroup width="24%"/> <tr> <th>Code</th> <th>Output</th> </tr> <tr> <td valign="top"><programlisting language="java">byte b = 127; b += 1; System.out.println("Result: " + b);</programlisting></td> <td valign="top"><screen>Result: -128</screen></td> </tr> <tr> <td valign="top"><programlisting language="java">byte b = -128; b += -1; System.out.println("Result: " + b);</programlisting></td> <td valign="top"><screen>Result: +127</screen></td> </tr> <tr> <td valign="top"><programlisting language="java">// Expecting 129 / 3 == +43 System.out.println("Result: " + getAverage((byte) 127, (byte) 1, (byte) 1));</programlisting></td> <td valign="top"><screen>Result: -42</screen></td> </tr> </informaltable> </listitem> <listitem> <para>Converting fractions to byte values is next on the list of troubles. The <code language="java">/=</code> operator will simply cut off fractional values rather then rounding them properly.</para> <para>Switching to real values we have <inlineequation> <m:math display="inline"> <m:mrow> <m:mrow> <m:mfrac bevelled="true"> <m:mi>1</m:mi> <m:mi>3</m:mi> </m:mfrac> <m:mo></m:mo> <m:mrow> <m:mo>(</m:mo> <m:mrow> <m:mi>1</m:mi> <m:mo>+</m:mo> <m:mi>1</m:mi> <m:mo>+</m:mo> <m:mi>0</m:mi> </m:mrow> <m:mo>)</m:mo> </m:mrow> </m:mrow> <m:mo>=</m:mo> <m:mi>0.66...</m:mi> </m:mrow> </m:math> </inlineequation> . Our byte valued method should thus return a value of 1 rather than 0. However:</para> <informaltable border="1"> <colgroup width="76%"/> <colgroup width="24%"/> <tr> <th>Code</th> <th>Output</th> </tr> <tr> <td valign="top"><programlisting language="java">System.out.println("Result: " + getAverage((byte) 1, (byte) 1, (byte) 0));</programlisting></td> <td valign="top"><screen>Result: 0</screen></td> </tr> </informaltable> </listitem> </orderedlist> <para>Solving these flaws requires using a data type behaving free of overflow errors with respect to the given context of summing up three byte values. Choosing <code>short</code> is sufficient for adding either <code language="java" xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Byte.html#MAX_VALUE">Byte.MAX_VALUE</code> or <code language="java" xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Byte.html#MIN_VALUE">Byte.MIN_VALUE</code> even three times in a row.</para> <para>Dividing by 3 should be a floating point rather than an integer operation to avoid cutting off fractional values. On top we finally use the <classname xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Math.html">Math</classname><code language="java">.</code><methodname xlink:href="https://freedocs.mi.hdm-stuttgart.de/lib/openjdk-21-doc/api/java.base/java/lang/Math.html#round(double)">round(double)</methodname> method avoiding rounding errors like the one shown previously.</para> <para>Finally we need a cast for converting back the rounded value's type <code language="java">double</code> to the method's return type <code language="java">byte</code>. The final result reads:</para> <programlisting language="java">public static byte getAverage(final byte a, final byte b, final byte c) { short sum = a; sum += b; sum += c; final double avg = sum / 3.; // Floating point rather than integer division return (byte) Math.round(avg); } // Note: final short sum = a + b + c does not even compile as being explained at // https://freedocs.mi.hdm-stuttgart.de/sd1_sect_arithmeticOperators.html#sd1_explainNoByteByteOperator</programlisting> <para>Given our sum being within range [-3 * -128, 3 * 127] dividing by three guarantees <code language="java">avg</code> to be within [-128, 127]. The <code language="java">(byte)</code> cast will thus safe with respect to overflow problems of our returned value.</para> </answer> </qandaentry> </qandadiv> </qandaset> </section> </section>