Class members and methods

Figure 268. Club membership objectives Slide presentation Create comment in forum
  • Each club member has got a name.

  • Each Member has got an ascending unique membership number.

  • The overall club's member count needs to be accounted for.

Solution:

  • Class level: Advance club's member count by each new member.

  • Instance level: New instances receive current member count.


Figure 269. Implementing club members. Slide presentation Create comment in forum
public class ClubMember {

  final private String name;

  public ClubMember(final String name) {
    this.name = name;
  }
  public String getDetails() {
    return "Member " + name;
  }
}

Figure 270. Showing membership info. Slide presentation Create comment in forum
final ClubMember
   john = new ClubMember("John"),
  karen = new ClubMember("Karen");

System.out.println(john.getDetails());
System.out.println(karen.getDetails());
Member John
Member Karen

Figure 271. Implementing membership numbers. Slide presentation Create comment in forum
emphapublic class ClubMember {

  static  private int memberCount = 0;

  final private int memberNumber; 
  final private String name;

  public ClubMember(final String name) {
    this.name = name;
    memberNumber = ++memberCount; 
  }
  public String getDetails() {
    return "Member " + name + ", member number " + memberNumber ;
  }
}

The keyword static defines memberCount as a class variable keeping track of the club's overall member count.

memberNumber and name being defined as instance variables.

On creating a new instance of ClubMember two actions happen:

  1. The overall memberCount variable is being incremented by one.

  2. The new club's overall member count is being assigned to the current instance.

Accessing an individual member's membership number.


Figure 272. Showing membership numbers. Slide presentation Create comment in forum
final ClubMember
   john = new ClubMember("John"),
  karen = new ClubMember("Karen");

System.out.println(john.getDetails());
System.out.println(karen.getDetails());
Member John, member number 1
Member Karen, member number 2

Figure 273. Accessing the club's overall member count? Slide presentation Create comment in forum
public class ClubMember {

  static private int memberCount = 0;
  ...
  public ClubMember(final String name) {
    this.name = name;
    memberNumber = ++memberCount;
  }
  static public int getMemberCount()  {
    return memberCount; 
  }
  ...
}

getMemberCount() being defined as class method by virtue of the static keyword.

Class (static) methods can only access class (static) variables.


Figure 274. Accessing the club's member count Slide presentation Create comment in forum
final ClubMember
   john = new ClubMember("John"),
  karen = new ClubMember("Karen"),
  petra = new ClubMember("Petra");

System.out.println(karen.getDetails());

System.out.println("Club's member count:"
   + ClubMember.getMemberCount());
// Good: Prevent tampering memberCount
// variable.
Member Karen, member number 2
Club's member count:3

Figure 275. Do we really require an instance? Slide presentation Create comment in forum
public class Helper {

  public int maximum(int a, int b) {
    if (a < b) {
      return b;
    } else {
      return a;
    }
  }
}
final Helper help = new Helper();

System.out.println("Maximum: " +
            help.maximum(-3, 5));
Maximum: 5

Observation: Instance state irrelevant.


Figure 276. Favour class method over instance method Slide presentation Create comment in forum
public class Helper {

  static public int
     maximum(int a, int b) {
    if (a < b) {
      return b;
    } else {
      return a;
    }
  }
}
System.out.println("Maximum: " +
     Helper.maximum(-3, 5));
Maximum: 5

Figure 277. Syntax accessing class members Slide presentation Create comment in forum
Class Variable

{class name}.{variableName}

Class Method

{class name}.{methodName}([parameter])


Figure 278. static / non-static wrap up Slide presentation Create comment in forum
public class X {
  int a; 
  static int b; 

Variable a defined once per instance of class X.

Variable b defined once per class X.


exercise No. 96

Class vs. instance Create comment in forum

Q:

  1. Is it possible to implement getDetails() from Figure 271, “Implementing membership numbers. ” as a class method by adding static?

  2. Is it possible to remove the static modifier from getMemberCount() in Figure 273, “Accessing the club's overall member count? ”?

A:

  1. Adding static yields:

    public class ClubMember {
     ...
      final private int memberNumber; // Instance variable
      final private String name;      // Instance variable
    ...
      static public String getDetails() { // Class method
        return "Member " + name + ", member number " + memberNumber;
      }
    }

    The above code does not compile: The two variables name and memberNumber are instance variables. Trying to access these from a static context results in two compile time error messages:

    model/ClubMember.java:20: error: non-static variable name cannot
      be referenced from a static context
        return "Member " + name + ", member number " + memberNumber;
                           ^
    model/ClubMember.java:20: error: non-static variable memberNumber
      cannot be referenced from a static context
        return "Member " + name + ", member number " + memberNumber;
                                                       ^
    2 errors

    Each member is being defined by its name and member number. static methods are being defined on class rather than on instance level. According to Class Method execution happens by calling ClubMember.getDetails(). There is thus no instance involved and consequently both instance variables name and memberNumber do not exist in any static context.

  2. Defining getMemberCount() as an instance rather than a class method is possible albeit discouraged:

    public class ClubMember {
    
      static private int memberCount = 0;
     ...
      public int getMemberCount() {
        return memberCount;
      }
     ...
    }

    Instance methods may access class variables. However calling the method now requires an instance:

    final ClubMember
       john = new ClubMember("John"),
      karen = new ClubMember("Karen"),
      petra = new ClubMember("Petra");
    
    System.out.println("Club's headcount:" + john.getMemberCount());

    This is actually a regression with respect to the static class method variant since the number of club members in fact does not depend on any individual member instance.

    We may reveal this changes futility by:

    final ClubMember
       john = new ClubMember("John"),
      karen = new ClubMember("Karen"),
      petra = new ClubMember("Petra");
    
    System.out.println("Club's headcount:" + john.getMemberCount());
    System.out.println("Club's headcount:" + karen.getMemberCount());
    System.out.println("Club's headcount:" + petra.getMemberCount());

    All three calls to getMemberCount() will yield he same value 3 referring to a total amount of three club members being created so far.

    Even worse: Without creating an instance of ClubMember we can no longer access the club's overall member count. But even without any member instance we still have a valid member count of zero.

exercise No. 97

Distinguishing leap- and non-leap years Create comment in forum

Q:

In Leap years you already started a leap year related exercise. This exercise is about wrapping your implementation into a method:

/**
 * Characterizing a given year either as leap year or
 * non- leap year
 *
 * @param year The year in question.
 * @return true if the year parameter is a leap year, false otherwise.
 */
public static boolean isLeapYear(int year) {
     ...
}

Write unit tests prior to actually implementing boolean isLeapYear(int year)!

After finishing you should also be able to test your implementation manually:

public static void main(String[] args) {
  System.out.println("Is 1800 a leap year? " + isLeapYear(1800));
  System.out.println("Is 2000 a leap year? " + isLeapYear(2000));
  System.out.println("Is 2016 a leap year? " + isLeapYear(2016));
}

This should produce the following output:

Is 1800 a leap year? false
Is 2000 a leap year? true
Is 2016 a leap year? true

A:

We start by a dummy implementation:

public static boolean isLeapYear(int year) {
  return true; // Wrong in most cases, we yet don't care.
}

This enables us writing unit tests beforehand:

/**
 * Testing leap year behaviour.
 */
public class LeapYearTest {
   /**
    * Test for leap years
    */
   @Test
   public void testLeapYearPositive() {
      assertTrue(LeapYear.isLeapYear(2000));
      assertTrue(LeapYear.isLeapYear(1984));
   }

   /**
    * Test for non-leap years
    */
   @Test
   public void testLeapYearNegative() {
      assertFalse(LeapYear.isLeapYear(2001));
      assertFalse(LeapYear.isLeapYear(1800));
   }
}

Obviously all negative tests will fail. We now implement the desired method:

public static boolean isLeapYear(int year) {
  if (year % 400 == 0) {                    // Every 400 years we do have a leap year.
    return true;
   } else if (year % 4 == 0 &&  0 != year % 100) { // Every 4 years we do have a leap
     return true;                                  // year unless the year in
                                                   // question is a multiple of 100.
   } else {
     return false;
   }
}

This one is easy to read. Experienced programmers however prefer compact code:

public static boolean isLeapYear(int year) {
  return
    year % 400 == 0 ||                  // Every 400 years we do have a leap year.
    year % 4 == 0 &&  0 != year % 100;  // Every 4 years we do have a leap year
                                        // unless the year in question ...
}

exercise No. 98

A method for printing square numbers using for, while and do ... while Create comment in forum

Q:

You already did exercises on printing mathematical tables. This exercise is about decomposing tasks into methods thereby improving code readability. We also explore using different loop types.

Consider the following example:

public class LoopExample {

  public static void main(String [] args) {
    squareNumbers(14);
  }

  /**
   * Compute all square numbers starting from 4 in steps of 3 being smaller
   * than a given limit. The results are being written to standard output.
   * Implemented by a for -loop.
   *
   * @param limit An upper exclusive bound for the highest number to be squared..
   */
  public static void squareNumbers(final int limit) {
    System.out.println("Computing square numbers");
    for (int i = 4; i < limit; i += 3) {
      System.out.println("i = " + i + ", i * i = " + i * i);
    }
    System.out.println("Finished computing square numbers");
  }
}

Re-implement the above code in two different ways:

  1. while (...) {...} loop:

      ...
    public static void while_squareNumbers(final int limit) {
      System.out.println("Computing square numbers");
    ...
      while (...) {
    ...
      }
      System.out.println("Finished computing square numbers");
    } ...
  2. do {...} while(...) loop:

      ...
    public static void while_squareNumbers(final int limit) {
      System.out.println("Computing square numbers");
    ...
      do {
       ...
      } while(...);
    
      System.out.println("Finished computing square numbers");
    } ...

Caveat: The do {...} while(...) part is a little bit tricky. Read the method's documentation precisely to avoid a common pitfall.

Do you have a comment choosing the right type of loop?

A:

The while loop is actually quite straightforward to implement:

public class LoopExample {
  ...
  public static void while_squareNumbers(final int limit) {
    System.out.println("Computing square numbers");
    int i = 4;
    while (i < limit) {
      System.out.println("i = " + i + ", i * i = " + i * i);
      i += 3;
    }
    System.out.println("Finished computing square numbers");
  } ...

Its tempting to implement a do ... while in a similar fashion:

public class LoopExample {
  ...
  public static void doWhile_squareNumbers(final int limit) {
    System.out.println("Computing square numbers");
    int i = 4;
    do {
      System.out.println("i = " + i + ", i * i = " + i * i);
      i += 3;
    } while (i < limit);
    System.out.println("Finished computing square numbers");
  } ...

This implementation however is flawed: If we call doWhile_squareNumbers(3) we still receive one line of output. But according to the documentation no output is to be expected. Whatever the argument is, at least one output line gets printed. To avoid this error the loop has to be enclosed by an if- statement:

public static void doWhile_squareNumbers(final int limit) {
  System.out.println("Computing square numbers");
  int i = 4;
  if (i < limit) { // Needed !!!
    do {
      System.out.println("i = " + i + ", i * i = " + i * i);
      i += 3;
    } while (i < limit);
  }
  System.out.println("Finished computing square numbers");
}

This required if-clause reminds us that a do {...} while (...) is an ill-suited choice here in comparison to a while(...){...} or a for(...){...} loop.

Actually a for(...){...} loop is the best choice here since the number of iterations is known in advance, the increment is constant and it allows for initialization.