Laboratory Notebook

Chapter 7 - More about Methods

Your name: | |

Your email address: | |

Your student ID number: |

Once this form has been customized for your
institution, you can use this button

To gain experience in

- tracing the flow of a method's execution
- method naming and commenting
- parameter passing
- determining the scope of variables
- using
`static`methods - decomposing complex tasks into simpler ones
- designing methods that solve practical problems
- programming recursive methods

Consider the following methods:

public static String replace(String s, String a, String b) public static double canVolume(double h, double r)

and these variables:

String greeting = Hello!" int a = 10; int b = 4;

What is wrong with each of the following method calls ?

`greeting = replace("Hello?", "?");`

`greeting = replace("Goodaye", a, b)`

`greeting = canVolume(a, b)`

In Java, a method cannot modify contents of any variables that are
passed into it. For example, consider this call to the procedure `f`:

Rectangle r = . . .; int n = . . .; . . . f(r, n)

After the call, `r` still refers to the same Rectangle object as
before the call, and `n` still contains the same number as before
the call.

The procedure `f` can modify the state of the Rectangle object,
for example, move it to another location. But it can't replace the object
with a different one.

The procedure cannot modify the value of `n` at all.

- In Java, it is not possible to write a procedure
`triple`in Java that achieves the following. Explain.int a = 4; triple(a); /* now a is 12 */

- Can you solve this problem by writing a method instead? How?

- Is it possible to write a procedure
`triple`in Java that achieves the following? Explain.Rectangle r = new Rectangle(0, 0, 10, 20); triple(r); /* now r's width is 30 */

- Is it possible to write a procedure
`swap`in Java that achieves the following? Explain.String a = "Adam"; String b = "Bruce"; swap(a, b); /* now a is Bruce, b is Adam */

In methods with more complicated branching of control, one way to insure
a reasonable return value is to gather together all the possibilities and
issue only one `return` statement from the very end of the block
statement. Rewrite the `pointsOfCompass` method as follows:

- Introduce an additional variable
`string directionString` - Be more clever about the logic--first compute the major direction (north, east, south, west), then append an east or west if necessary
- Return the
`directionString`from the end of the method only

public class Compass { /** * Construct a Compass * @param d the compass needle angle in degrees */ public Compass(double d) { degrees = d; } /** * Convert a numeric compass position to it's verbal equivalent * @param degrees the compass needle angle in degrees * @return the value as a compass direction ("N", "NE", ...) */ public String pointsOfCompass() { double octant = (degrees % 360) / 45.0 - 0.5; if (octant >= 7) return "North West"; else if (octant >= 6) return "West"; else if (octant >= 5) return "South West"; else if (octant >= 4) return "South"; else if (octant >= 3) return "South East"; else if (octant >= 2) return "East"; else if (octant >= 1) return "North East"; else if (octant >= 0) return "North"; else return "North West"; } private double degrees; }

Global (or `static`) variables may "work", but the
advantages they offer are outweighed by the confusion they can cause.
Since all methods can set a global variable, it is often difficult to find
the guilty party if the global variable is set to the wrong value.

Consider this example.

public class Max { /** * Updates maximum if parameter is larger * @param a the value to compare against maximum * @remark Uses static int maximum */ public static void set_max(int a) { if (maximum < a) { maximum = a; } } public static int max3(int i, int j, int k) { set_max(i); set_max(j); set_max(k); return maximum; } public static void main(String[] args) { ConsoleReader console = new ConsoleReader(System.in); System.out.println("Please enter the first integer:"); int i = console.readInt(); System.out.println("Please enter the second integer:"); int j = console.readInt(); System.out.println("Please enter the third integer:"); int k = console.readInt(); int maximum = max3(i, j, k); System.out.println("The maximum is " + maximum); } public static int maximum; }

Test this program. Does it work?

What would happen if your program computed the maximum of two data sets? Would it still work?

Re-write ` max3() ` to avoid the use of global variables, and to
preserve the logic of the method.

Generally, we want to encourage you to define a variable when you first need it, but you have to pay attention to the scope. Find what's wrong with this method's variable scoping, then fix it.

/** * Select the maximum of three integer values * @param i an integer * @param j an integer * @param k an integer * @return the maximum of i, j, and k */ public static int maximum(int i, int j, int k) { if (i > j) { int a; a = i; } else { a = j; } if (k > a) { return k; } else { return a; } }

Why are the following methods badly named? What names would be better?

`double 2toTheN(int n)`

/* compute a power of 2 */`double(int n)`

/* return twice the value of`n`*/`double rt(double x)`

/* computes the square root */

Sooner or later, you'll encounter cryptically named and uncommented work like the following.

public static bool cw(Rectangle r1, Rectangle r2) { return r1.getWidth() == r2.getWidth(); } public static bool ch(Rectangle r1, Rectangle r2) { return r1.getHeight() == r2.getHeight(); } public static bool c4dup(Rectangle r1, Rectangle r2) { return cw(joe, mary) && ch(joe, mary); } public static void main(String[] args) { Rectangle r1; Rectangle r2; . . . if(c4dup(r1, r2)) System.out.println("Same"); else System.out.println("Different"); }

What do these methods do ?

Rewrite them with comments and more descriptive method and parameter names. Use:

/** *purpose* @param * @return */

Throw an `IllegalArgumentException` in the following example to
signal that an improper input has occurred and to prevent the bad
parameters from being utilized by the function.

public class PrecondExercise { /** * Compute seconds from midnight * @param hours hour of a clock time (between 0 and 23) * @param min minutes of a clock time (between 0 and 59) * @return the number of seconds between midnight and the clock time */ public static int convertToSec(int hours, int min) { /* your work here -- assert that hours and min are within input range */ return hours * 3600 + min * 60; } /** * Compute the number of seconds between two clock times * @param hfrom the hours of the earlier time * @param mfrom the minutes of the earlier time * @param hto the hours of the later time * @param mto the minutes of the later time * @return the number of seconds between them */ public static int secondsBetween(int hfrom, int mfrom, int hto, int mto) { int secs = convertToSec(hto, mto) - convertToSec(hfrom, mfrom); /* your work here -- assert that the from time is before the to time */ return secs; } public static void main(String[] args) { ConsoleReader console = new ConsoleReader(System.in); System.out.println("Input start hours:"); int startHr = console.readInt(); System.out.println("Input start minutes:"); int startMin = console.readInt(); System.out.println("Input end hours:"); int endHr = console.readInt(); System.out.println("Input end minutes:"); int endMin = console.readInt(); System.out.println(secondsBetween(startHr, startMin, endHr, endMin) + " seconds elapsed"); } }

How does your program handle

- input error, ie.
`start > end`?

`hours > 23`or`minutes < 0`

Consider a method `int digits(int)` which finds the number of
digits needed to represent an integer. For example, `digits(125)`
is 3 because 125 has three digits (1, 2, and 5). The algorithm is defined
as:

if n < 10, then digits(n) equals 1. Else, digits(n) equals digits(n / 10) + 1.

(Why? If n is less than 10, one digit is required. Otherwise, n requires one more digit than n/10.)

For example, if called as `int num_digits = digits(1457)`, the
following trace results:

digits(1457) = digits(145) + 1 = digits(14) + 1 + 1 = digits(1) + 1 + 1 + 1 = 1 + 1 + 1 + 1

Do a trace of `digits(32767)`

Write `int digits(int n)` to be called by the following `main()`:

public static void main(String[] args) { ConsoleReader console = new ConsoleReader(System.in); System.out.println("Please enter a number:"); int testValue = console.readInt(); int ndigits = digits(testValue); System.out.println("You need " + ndigits + " digits to represent " + testValue + " in decimal"); }

Don't forget to send your answers when you're finished.