Module 6: Methods I


Objectives

 

By the end of this module, for simple HelloWorld-like programs, you will be able to:

 


An example with method calls

 

Consider the following program:

 

In-Class Exercise 1: Type, compile and execute the above program.
 

Now let's point out a few things:

 

In-Class Exercise 2: Write your own animal sound that uses one method at least thrice with an exclamation mark at the end, e.g., print the big version of BAAA!. Once your program is working, say the sound out aloud to the class.
 

Next, let's see how methods "work" by drawing an analogy:

 

Using numbers, let's trace each step in sequence:

 

In-Class Exercise 3: Try these questions for the above program:

 


Calling methods from other methods

 

Consider this program:

  • Yes, we can write our methods that call our own methods.
  • Incidentally, did you notice the escape sequences?
           => We improved the output.
 

In-Class Exercise 4: Re-write your own animal sound using this idea. That is, use a single method for the letter that repeats, then call a single method from main that then has the repetitive method calls.
 

Once again, let's trace through some steps:

 

In-Class Exercise 5: Which step corresponds to the question mark above? Where in the program would we be at the 15 step?
 

Mental execution:

  • We will use the term mental execution for the above exercise of tracing through the execution without actually compiling and running the program.

  • Note: Mental execution is extremely important in developing programming skill
           => Please be sure to practice this with every program you read or write.

  • We can't emphasisize this enough. Really.
 


Method parameters

 

To see how methods work, let's start with a simple example:

 

In-Class Exercise 6: Edit, compile and execute the above program. Then, just before the declaration of j but after the first invocation of incrementAndPrint in main, print the value of i.
 

In-Class Exercise 7: Print out the value of i within incrementAndPrint and see what happens.
 

Let's examine method parameters step by step:

  • First, method names are like variable names: usually a collection of letters and numbers.
           => e.g., incrementAndPrint.

  • The capitalization inside the name (incrementAndPrint) has no effect on the compilation/execution
           => It's merely for readability.

  • Next, let's distinguish between invocation

    and definition:

  • Let's focus on as few aspects of the definition.

    When you read this, say to yourself

    • "The method takes one parameter, an integer."
    • "The method returns nothing" (void).

  • Next, let's examine the flow of execution with the first invocation:

  • At the next invocation:

  • What's important to remember: the value in j gets copied into the parameter variable k.
           => Thus, the value in j is not affected inside incrementAndPrint.

  • It's possible to use the same name for the parameter variables, even though they are different:

    Here, we say that the scope of the variables i and j in the method incrementAndPrint is limited to all the code inside the method.

 

In-Class Exercise 8: Fill in the code in the method below so that the output of the program is:

  *****
  ***
  *
  

 


Multiple parameters

 

Consider the following example:

  • Here, the method checkPythagoreanTriple is defined with three parameter variables.
           => All happen to identically be int's but don't have to be.

  • The values at the invocation are given to the method in the order the parameters are declared:

    • The first value in the invocation goes to the first parameter variable.
    • The second value in the invocation goes to the second parameter variable.

  • A method can be invoked in various ways:

 

In-Class Exercise 9: Fill in the code in the method below so that the output of the program is 3 and 5, respectively.

 


Reading and Writing

 

First, let's talk about writing:

  • As usual, when writing methods, type in both parens and both braces before typing what's in between.

  • Generally, use the style we have been using:
    • Proper alignment of braces under the p of public.
    • A space between the method name and the parens.

  • You can make up method names, but follow the preferred style:
    • Start with a lowercase letter.
    • Capitalize the start of different parts of the name.

  • Note: class names (like AnimalSounds) should start with a capital letter.
 

An important thing to understand about identifiers:

  • Consider the method name printBigM.

  • This is a name (identifier) we chose.

  • We could just as easily have used myCrazyMethod:

  • In other words, the compiler does not look into the English meaning of identifiers.

  • We choose identifiers to help us read programs.
 

A few more writing issues:

  • It is possible to write a method declaration before or after any invocation. For example, we could have written:

  • There are three conventions typically used:
    • Always declare methods before their first invocation.
    • Try to declare methods near their first invocation (just before or just after).
    • Or, group method declarations according to common theme.
      (For large classes with many methods.)

  • For main, there are also two conventions:
    • main is the first method in the class.
    • main is the last method in the class.

  • What cannot be done: write a method declaration outside a class:

  • Also, we cannot declare a method inside another method, as in:

  • Not that you'd want to, but you can declare a method but not invoke it anywhere.

  • You can declare any number of methods inside a class.
 

In-Class Exercise 10: What would happen if we changed the order of method invocation? For example:

 

About name clashes:

  • Java allows two methods to have the same, provided they are different in some ways defined by the language.

  • This is a somewhat complex issue at this point, so we will simply give different method names.

  • One can also use the class name as a method name, but this is considered poor stylistic practice.
 


Return Values

 

Observe the following program:

  public class ReturnValues {
      public static void main(String[] args)
      {
          int val;

          val = square(8);
          System.out.println(val);
      }

      public static int square(int x)
      {
          return x * x;
      }
  }
  • What's the output?

  public class ReturnValues {
      public static void main(String[] args)
      {
          int val;

          val = square(8);
          System.out.println(val);
      }

      public static int square(int x)
      {
          return x * x;
      }
  }
  • Method return values are specified with the type in the method signature, and if this type is not void, the method must include at least one return statement.

  • The type of the expression that is returned from the method must match the return type of the method. The expression that invokes the method must use the return value as the type that is returned.

  public class ReturnValues {
      public static void main(String[] args)
      {
          int val;

          val = square(8); /* square(8) evaluates to 8 * 8, thus 64 */
          System.out.println(val);
      }

      public static int square(int x)
      {
          return x * x;
      }
  }
  • When reading methods and method invocations, you want to follow, statement by statement, what's executing. When you hit a return statement, replace the value being returned where the method is invoked.

  public class ReturnValues {
      public static void main(String[] args)
      {
          int val, x = 8;

          val = square(8);
          System.out.println(val);
          x = square(x);
          System.out.println(x);
          System.out.println(square(8));
      }

      public static int square(int x)
      {
          return x * x;
      }
  }
  • Variables in one function are different from variables in another function. A variable only exists within enclosing own {...}.

  • You can pass constants or variables as arguments.

  • Methods can be invoked anywhere a variable of the method's return type can be used.

  public class SimpleDivide {
      public static void main(String[] args)
      {
          System.out.println(div(40, 4));
          System.out.println(div(40, 10));
          System.out.println(div(40, 0));
      }

      public static double div(int numerator, int divisor)
      {
          return (double)numerator/divisor;
      }
  }
 

In-Class Exercise 11: What does the above program print out? Type it out, and run it. Does the output meet your expectation? How could you fix it, if it doesn't?
 

 

  public class SimpleDivide {
      public static void main(String[] args)
      {
          System.out.println(div(40, 4));
          System.out.println(div(40, 10));
          System.out.println(div(40, 0));
      }

      public static double div(int numerator, int divisor)
      {
          if (divisor == 0) {
              return 0;
          }
          return (double)numerator/divisor;
      }
  }
  • Multiple return statements are fine!

  • Each return statement exits the method, returning the value they specify.

 


Testing your Programs

 

Testing programs is the act of making sure that your implementation does what you want it to do. Technically, we usually have a "specification" for what we are supposed to implement. Testing checks if our implementation adheres to the specification. Inputs to test are always:

  • "Edge cases": Are there are values that will test your conditionals well? Examples: zero in the divide example above, the lat/lon boundaries in your coordinate transformation code?

  • Invalid inputs: Are there any inputs that should not be valid? Examples: lat/lon outside of the bounding box. Question: What do you return in such cases?

  • Valid inputs you know the proper return value for. Examples: lat/lon directly in the center of the bounding box...the pixel should be the center of the screen!

 

In-Class Exercise 12 The equation for a line is y = mx + b. Write a function with the following prototype:

      public static double solveForX(double y, double m, double b)
How will you test the function? What values of y, m, and b should you choose? Choose at least 4 sets of inputs.
 

  • assert statements in Java are used to check that your methods are doing what they're supposed to.

  public class SimpleDivide {
      public static void main(String[] args)
      {
          assert (div(40, 4) == 10) : "divide doesn't properly divide 40 and 4";
          assert (div(40, 10) == 4) : "divide doesn't properly divide 40 and 10";
          assert (div(40, 0)) : "divide by zero broken";
      }

      public static double div(int numerator, int divisor)
      {
          if (divisor == 0) {
              return 0;
          }
          return (double)numerator/divisor;
      }
  }
 

In-Class Exercise 13:

Break the example:

  • Return only numerator.

  • Remove the conditional.

What happens?

 

In-Class Exercise 14: In module 5, you implemented three different versions of BMI calculations with different conditional structures. It's time to test these implementations!

  1. Create three separate methods, one for each version of your BMI calculations.
  2. What should the parameters to these methods be?
  3. What should the return value from these methods be?
  4. How can you test your implementations?
 


When things go wrong

 

 

In-Class Exercise 15: What is the compiler error you get when a method is accidentally declared outside a class?
 

In-Class Exercise 16: What is the compiler error you get when a method is accidentally declared inside another method?
 

In-Class Exercise 17: What is the compiler error if we misspell printBigM in the first AnimalSounds program?