diff --git a/Doc/Sd1/coreClasses.xml b/Doc/Sd1/coreClasses.xml index a4e54ec585143c3c5fc105e671956f6299bb900a..99d8e2f2df261520917e5dcd9a7541a29515d15d 100644 --- a/Doc/Sd1/coreClasses.xml +++ b/Doc/Sd1/coreClasses.xml @@ -73,26 +73,35 @@ <title>Operator == and <methodname>equals()</methodname></title> <informaltable border="0"> + <colgroup width="38%"/> + + <colgroup width="62%"/> + <tr> - <td valign="top"><programlisting language="java">String s1 = new String("Kate"); -String s2 = new String("Kate"); + <th>Primitive type</th> -System.out.println("==: " + (s1 == s2)); -System.out.println("equals: " + s1.equals(s2));</programlisting></td> + <th>Object</th> + </tr> - <td valign="top"><programlisting language="java">int a = 12; -int b = 12; + <tr> + <td valign="top"><programlisting language="java">int a = 12, b = 12; // equal values System.out.println("==: " + (a == b)); -// No equals(...) equivalent for -// primitive types</programlisting></td> +// No equals(...) method equivalent +// for primitive types</programlisting></td> + + <td valign="top"><programlisting language="java">String s1 = new String("Kate"), + s2 = new String("Kate"); + +System.out.println(" ==: " + (s1 == s2)); +System.out.println("equals: " + s1.equals(s2));</programlisting></td> </tr> <tr> - <td valign="top"><screen>==: false -equals: true</screen></td> - <td valign="top"><screen>==: true</screen></td> + + <td valign="top"><screen> ==: false +equals: true</screen></td> </tr> </informaltable> </figure> @@ -109,7 +118,14 @@ equals: true</screen></td> <listitem> <para>The <code language="java">==</code> operator acting on objects - compares for object identity.</para> + compares for equality of reference values and thus for object + identity.</para> + </listitem> + + <listitem> + <para>The <code language="java">==</code> operator acting on objects + does <emphasis role="red">not</emphasis> check whether two objects + carry semantically equal values.</para> </listitem> <listitem> diff --git a/Doc/Sd1/languageFundamentals.xml b/Doc/Sd1/languageFundamentals.xml index 17f555452a21257a836690be0c0911ce10da932a..7d7cfa441c2e82b55dc5d087165c0260a838a0c2 100644 --- a/Doc/Sd1/languageFundamentals.xml +++ b/Doc/Sd1/languageFundamentals.xml @@ -4266,16 +4266,56 @@ short sum = a + 7; <co linkends="sd1_co_expressionTypeIntToShort-2" xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-B">short</code>.</para> <para>The very same argument seems to apply for the expression - <code language="java">4 + 7</code> even better: This time the plus - operator acts on two <code language="java" + <code language="java">4 + 7</code> even more: This time the plus + operator acts on even two <code language="java" xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-C">int</code> - operands. However the <xref linkend="glo_Java"/> compiler is - <quote>clever</quote> enough casting the <code language="java" - xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-C">int</code> - result 11 to the <code language="java" + operands. However in contrast to the former assignment this time + <emphasis>both</emphasis> operands are static. The 4 + 7 + expression's value of 11 is being calculated at compile time. + Since 11 of type <code language="java">int</code> is within + <inlineequation> + <m:math display="inline"> + <m:mrow> + <m:mo>[</m:mo> + + <m:mrow> + <m:mrow> + <m:mo>-</m:mo> + + <m:msup> + <m:mi>2</m:mi> + + <m:mi>15</m:mi> + </m:msup> + </m:mrow> + + <m:mo>,</m:mo> + + <m:mrow> + <m:mrow> + <m:mo>-</m:mo> + + <m:msup> + <m:mi>2</m:mi> + + <m:mi>15</m:mi> + </m:msup> + </m:mrow> + + <m:mo>-</m:mo> + + <m:mi>1</m:mi> + </m:mrow> + </m:mrow> + + <m:mo>]</m:mo> + </m:mrow> + </m:math> + </inlineequation> the compiler will safely cast this value to + the <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> - variable <code language="java">sum</code> without any loss of - information.</para> + variable <code language="java">sum</code> without information + loss.</para> </answer> </qandaentry> </qandadiv> @@ -4300,7 +4340,8 @@ short sum = a + 7; <co linkends="sd1_co_expressionTypeIntToShort-2" <para>The divide operator acts on two <code language="java" xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-C">int</code> literal values 8 an 9. Thus irrespective of the possibly intended - floating point result the resulting type is int .</para> + floating point result the resulting type is <code + language="java">int</code> .</para> <para>According to <uri xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3-300-A-2">https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3-300-A-2</uri> @@ -4841,8 +4882,8 @@ System.out.println("Difference: " + difference);</programlisting><screen>Differe double radius = 2.31; // A circle having a radius (given e.g. in mm). double pi = 3.1415926; // Constant relating a circle's radius, //perimeter and area. - - // TODO: Write the circle's area to standard output + + System.out.println( <emphasis role="red">/* TODO: Write the circle's area to standard output */</emphasis>); }</programlisting> <tip> @@ -4950,36 +4991,212 @@ System.out.println("A circle of radius " + radius + " will cover an area of " + </question> <answer> - <para>The solution is straightforward. We add the <code + <para>The solution is straightforward. We just add a <code language="java" xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4">final</code> modifier to the definition of our variable <code - language="java">pi</code>. In addition we use capital letters - <code language="java">PI</code> reflecting the naming convention - for constants:</para> + language="java">pi</code>:</para> - <programlisting language="java" linenumbering="numbered">final double PI = 3.141592653589793; + <programlisting language="none" linenumbering="numbered"><emphasis + role="red">final</emphasis> <co + linkends="sd1_listing_final_guard_pi-1" + xml:id="sd1_listing_final_guard_pi-1-co"/> double <emphasis + role="red">pi</emphasis> = 3.141592653589793; +... +<emphasis role="red">pi</emphasis> = -4; <co + linkends="sd1_listing_final_guard_pi-2" + xml:id="sd1_listing_final_guard_pi-2-co"/> +...</programlisting> + + <calloutlist> + <callout arearefs="sd1_listing_final_guard_pi-1-co" + xml:id="sd1_listing_final_guard_pi-1"> + <para>A <code language="java" + xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4">final</code> + modifier prohibits subsequent variable assignments thus + keeping its initially assigned value constant.</para> + </callout> + + <callout arearefs="sd1_listing_final_guard_pi-2-co" + xml:id="sd1_listing_final_guard_pi-2"> + <para>The assignment attempt is being flagged as a compile + time error:</para> + + <para><computeroutput>Cannot assign a value to final variable + 'PI'</computeroutput></para> + </callout> + </calloutlist> + + <para>As a rule of thumb: Whenever you intend a variable not to + change after an initial assignment use <code language="java" + xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4">final</code> + declaring it to remain constant.</para> + + <para>In addition we may refactor our variable <code + language="java">pi</code> to use capital letters reflecting the + naming convention for constants. This is does not change program + execution in any way but enhances code readability:</para> + + <programlisting language="java" linenumbering="numbered">final double <emphasis + role="red">PI</emphasis> = 3.141592653589793; double radius = 2.3; // Computing a circle's area System.out.println("A circle of radius " + radius + " will cover an area of " + - PI * radius * radius); + <emphasis role="red">PI</emphasis> * radius * radius); -PI = -4; +<emphasis role="red">PI</emphasis> = -4; radius = 1.8; System.out.println("A circle of radius " + radius + " will cover an area of " + - PI * radius * radius);</programlisting> + <emphasis role="red">PI</emphasis> * radius * radius);</programlisting> + </answer> + </qandaentry> + </qandadiv> + </qandaset> - <para>Now our flawed assignment at line 6 will be flagged as a - compile time error:</para> + <qandaset defaultlabel="qanda" xml:id="sd1_qanda_weeks2seconds"> + <title>Turning weeks into seconds</title> - <para><computeroutput>Cannot assign a value to final variable - 'PI'</computeroutput></para> + <qandadiv> + <qandaentry> + <question> + <para>Consider:</para> - <para>As a rule of thumb: Whenever you intend a variable not to - change after an initial assignment use <code language="java" - xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4">final</code> - declaring it to remain constant.</para> + <programlisting language="java">final short + weeks = 2, + days = 3, + hours = 14, + minutes = 32, + seconds = 55; + +final int secondsElapsed = ...; // TODO: assign elapsed seconds corresponding to previous time frame. + +System.out.println(secondsElapsed);</programlisting> + + <para>Create an expression based on the variables <code + language="java">weeks</code>, <code language="java">days</code>, + <code language="java">hours</code>, <code + language="java">minutes</code> and <code + language="java">seconds</code> to calculate the number of seconds + elapsed for the given time period of two weeks, three days and so + on.</para> + + <para>After you have completed this task read about <link + xlink:href="https://eli.thegreenplace.net/2010/03/30/horners-rule-efficient-evaluation-of-polynomials#horner-s-rule">Horner's + rule</link> and try to improve your solution with respect to + execution time.</para> + </question> + + <answer> + <para>A straightforward solution reads:</para> + + <programlisting language="java">final short + weeks = 2, + days = 3, + hours = 14, + minutes = 32, + seconds = 55; + +final int secondsElapsed = + seconds + 60 * minutes + 60 * 60 * hours + 60 * 60 * 24 * days + 60 * 60 * 24 * 7 * weeks; + +System.out.println(secondsElapsed);</programlisting> + + <para>This requires four additions and 10 multiplications. We may + use:</para> + + <programlisting language="java">... +final int secondsElapsed = + seconds + 60 * (minutes + 60 * (hours + 24 * (days + 7 * weeks))); +...</programlisting> + + <para>This leaves us with four additions but just 4 instead of 10 + multiplications.</para> + + <para>Within the given context the difference in execution time + can be neglected. But in a different application the calculation + in question might have to be repeated millions of times giving + rise to a substantial gain with respect to total execution + time.</para> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + + <qandaset defaultlabel="qanda" xml:id="sd1_qanda_seconds2weeks"> + <title>Turning seconds into weeks</title> + + <qandadiv> + <qandaentry> + <question> + <para>This exercise is about reversing <xref + linkend="sd1_qanda_weeks2seconds"/> namely decomposing a given + value of elapsed seconds into weeks, days, hours, minutes and + seconds:</para> + + <programlisting language="java">final int secondsElapsed = 1521175; + +final int weeks = ...; // TODO +final int days = ...;// TODO +final int hours = ...;// TODO +final int minutes = ...;// TODO +final int seconds = ...;// TODO + +System.out.println(weeks + ", " + days + ", " + hours + ", " + minutes + ", " + seconds);</programlisting> + + <tip> + <para>As an example consider decomposing 192 seconds into + minutes and seconds:</para> + + <itemizedlist> + <listitem> + <para>Integer division 192 / 60 seconds yields 3 + minutes.</para> + </listitem> + + <listitem> + <para>We get the remaining seconds by virtue of the + remainder operator 192 % 60.</para> + </listitem> + </itemizedlist> + + <para>Thus 192 seconds equal 3 minutes and 12 seconds</para> + </tip> + </question> + + <answer> + <para>We extend the given minute calculation example to all 5 + desired values. For the sake of convenience the number of seconds + per minute, per hour and so on are being calculated + beforehand:</para> + + <programlisting language="java">final int secondsElapsed = 1521175; + +// Defining helpful constants +// +final int + secondsPerMinute = 60, // 60 minutes per hour + secondsPerHour = 60 * secondsPerMinute, // 3600 seconds per hour + secondsPerDay = 24 * secondsPerHour, // 86400 seconds per day + secondsPerWeek = 7 * secondsPerDay; // 604800 seconds per week + +int remainingSeconds = secondsElapsed; + +final int weeks = remainingSeconds / secondsPerWeek; +remainingSeconds = remainingSeconds % secondsPerWeek; + +final int days = remainingSeconds / secondsPerDay; +remainingSeconds %= secondsPerDay; + +final int hours = remainingSeconds / secondsPerHour; +remainingSeconds %= secondsPerHour; + +final int minutes = remainingSeconds / secondsPerMinute; +remainingSeconds %= secondsPerMinute; + +final int seconds = remainingSeconds; + +System.out.println(weeks + ", " + days + ", " + hours + ", " + minutes + ", " + seconds);</programlisting> </answer> </qandaentry> </qandadiv> diff --git a/Doc/Sd1/objectsClasses.xml b/Doc/Sd1/objectsClasses.xml index fcb37c0c269a31d3dc00acc0bc162531d233c1c9..4a94f0eff3fc9baaa27dce9c63168c32b7e3b22e 100644 --- a/Doc/Sd1/objectsClasses.xml +++ b/Doc/Sd1/objectsClasses.xml @@ -50,7 +50,7 @@ </listitem> <listitem> - <para>typically hide their implementation.</para> + <para>allow for implementation hiding.</para> </listitem> <listitem> @@ -3314,6 +3314,200 @@ public class Circle { </imageobject> </mediaobject> </figure> + + <qandaset defaultlabel="qanda" xml:id="sd1_qanda_seconds2weeks_Class"> + <title>Turning seconds into weeks part 2</title> + + <qandadiv> + <qandaentry> + <question> + <para>This is a follow-up exercise to <xref + linkend="sd1_qanda_seconds2weeks"/> implementing a corresponding + <classname>Timeperiod</classname> class. Consider the subsequent + example demonstrating both its constructor and + <methodname>toString()</methodname> method:</para> + + <informaltable border="0"> + <tr> + <td valign="top"><programlisting language="java">final Timeperiod t = new Timeperiod(112223); +System.out.println(92 + " seconds are equal to " + t);</programlisting></td> + + <td valign="top"><screen>92 seconds are equal to 1 day, 7 hours, 10 minutes and 23 seconds</screen></td> + </tr> + </informaltable> + + <para>Since the <methodname>toString()</methodname> method may + not be called at all it shall be implemented on demand. Tip: + create a suitable attribute being <code + language="java">null</code> initially. If + <methodname>toString()</methodname> is being called, first check + for <code language="java">null</code> and initialize it on + demand only.</para> + + <para>Furthermore the individual weeks, days, hours, minutes and + seconds should be implemented as readonly values using <code + language="java">final</code>:</para> + + <informaltable border="0"> + <tr> + <td valign="top"><programlisting language="java">final Timeperiod t = new Timeperiod(2310983); +System.out.print("weeks = " + t.weeks + + "\ndays = " + t.days + + "\nhours = " + t.hours + + "\nminutes = " + t.minutes + + "\nseconds = " + t.seconds);</programlisting></td> + + <td valign="top"><screen>weeks = 3 +days = 5 +hours = 17 +minutes = 56 +seconds = 23</screen></td> + </tr> + </informaltable> + + <para>In other words: The <classname>Timeperiod</classname> + class should be implemented as an <link + xlink:href="https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html">immutable</link>. + Thus once a <classname>Timeperiod</classname> instance has been + created it shall be impossible to alter the instance + <abbrev>i.e.</abbrev> changing its state.</para> + + <para>Use the following tests to check your implementation: + </para> + + <programlisting language="java">public class TimeperiodTest { + + // Helper methods for real tests. + static void assertPeriodEqualImplement(final int expectedSeconds, + final int expectedMinutes, + final int expectedHours, + final int expectedDays, + final int expectedWeeks, + final String expectedToString, + final Timeperiod period) { + Assert.assertEquals(expectedSeconds, period.seconds); + Assert.assertEquals(expectedMinutes, period.minutes); + Assert.assertEquals(expectedHours, period.hours); + Assert.assertEquals(expectedDays, period.days); + Assert.assertEquals(expectedWeeks, period.weeks); + + Assert.assertEquals(expectedToString, period.toString()); + + } + + static void assertPeriodEqual(final int expectedSeconds, + final int expectedMinutes, + final int expectedHours, + final int expectedDays, + final int expectedWeeks, + final String expectedToString, + final Timeperiod period) { + + // Testing period in question + assertPeriodEqualImplement( + expectedSeconds, expectedMinutes, expectedHours, expectedDays, expectedWeeks, expectedToString, + period); + + // Also testing copy constructor + assertPeriodEqualImplement( + expectedSeconds, expectedMinutes, expectedHours, expectedDays, expectedWeeks, expectedToString, + new Timeperiod(period)); + } + + /** + * Test constructor zero seconds. + */ + @Test + public void testZero() { + assertPeriodEqual( + 0,0,0,0,0, + "0 seconds", + new Timeperiod(0)); + } + + @Test + public void testMinute() { + assertPeriodEqual(0,1,0,0,0, + "1 minute and 0 seconds", + new Timeperiod(60)); + assertPeriodEqual(50,0,0,0,0, + "50 seconds", + new Timeperiod(50)); + assertPeriodEqual(12,1,0,0,0, + "1 minute and 12 seconds", + new Timeperiod(72)); + assertPeriodEqual(2,5,0,0,0, + "5 minutes and 2 seconds", + new Timeperiod(302)); + } + + @Test + public void testHour() { + assertPeriodEqual(0,0,2,0,0, + "2 hours, 0 minutes and 0 seconds", + new Timeperiod(7200)); + assertPeriodEqual(59,59,0,0,0, + "59 minutes and 59 seconds", + new Timeperiod(3599)); + assertPeriodEqual(40,1,1,0,0, + "1 hour, 1 minute and 40 seconds", + new Timeperiod(3700)); + } + + @Test + public void testVarious() { + assertPeriodEqual(1,3,4,1,6, + "6 weeks, 1 day, 4 hours, 3 minutes and 1 second", + new Timeperiod(3729781)); + + assertPeriodEqual(23,56,17,5,3, + "3 weeks, 5 days, 17 hours, 56 minutes and 23 seconds", + new Timeperiod(2310983)); + } +}</programlisting> + </question> + + <answer> + <para>Our implementation basically reads:</para> + + <programlisting language="java">public <link + xlink:href="https://gitlab.mi.hdm-stuttgart.de/goik/GoikLectures/blob/master/P/Sd1/Timeperiod/src/main/java/de/hdm_stuttgart/mi/sd1/Timeperiod.java">Timeperiod</link>(final Timeperiod timeperiod) { + + public final int seconds, minutes, hours, days, weeks; + // Constructors and toString() ... + +}</programlisting> + + <para>The <code language="java">final</code> modifier ensures + instances to be immutable requiring all values to be set within + any constructor. We thus decompose the desired number of seconds + into weeks, days, hours, minutes and remaining seconds:</para> + + <programlisting language="java">public <link + xlink:href="https://gitlab.mi.hdm-stuttgart.de/goik/GoikLectures/blob/master/P/Sd1/Timeperiod/src/main/java/de/hdm_stuttgart/mi/sd1/Timeperiod.java#L65">Timeperiod</link>(int seconds) { + + weeks = seconds / SECONDS_PER_WEEK; + seconds = seconds % SECONDS_PER_WEEK; // remaining seconds without weeks + + days = seconds / SECONDS_PER_DAY; + seconds %= SECONDS_PER_DAY; // remaining seconds without days + + hours = seconds / SECONDS_PER_HOUR; + seconds %= SECONDS_PER_HOUR; // remaining seconds without minutes + + minutes = seconds / SECONDS_PER_MINUTE; + this.seconds = seconds % SECONDS_PER_MINUTE; // remaining seconds +}</programlisting> + + <para>Notice the <code language="java">this.seconds</code> + qualification being required to disambiguate the constructor + parameter variable <code language="java">Timeperiod(int + seconds)</code> from <code + language="java">Timeperiod.seconds</code>.</para> + </answer> + </qandaentry> + </qandadiv> + </qandaset> </section> </section>