Class members and methods

Figure 242. Club membership objectives Slide presentation
  • 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 243. Implementing club members. Slide presentation
public class ClubMember {

  final private String name;

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

Figure 244. Showing membership info. Slide presentation
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 245. Implementing membership numbers. Slide presentation
public 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 246. Showing membership numbers. Slide presentation
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 247. Member creation steps Slide presentation

Figure 248. Accessing the club's overall member count? Slide presentation
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 249. Accessing the club's member count Slide presentation
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 250. Do we really require an instance? Slide presentation
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 251. static: Favour class method over instance method Slide presentation
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 252. Syntax accessing class members Slide presentation
Class Variable

{class name}.{variableName}

Class Method

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


Figure 253. static / non-static wrap up Slide presentation
public class X {
         int a; 
  static int b; 

Variable a defined once per instance of class X.

Variable b defined once per class X.


Figure 254. Finally understanding System.out.print(ln) Slide presentation
          
System.out.print(...)

Class System in package java.lang.

Class variable (static) out of type PrintStream in class System

One of 9 overloaded methods in class PrintStream.


exercise No. 104

Class vs. instance

Q:

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

  2. Is it possible to remove the static modifier from getMemberCount() in Figure 248, “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. 105

Distinguishing leap- and non-leap years

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. 106

A method for printing square numbers using for, while and do ... while

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 whileSquareNumbers(final int limit) {
      System.out.println("Computing square numbers");
    ...
      while (...) {
    ...
      }
      System.out.println("Finished computing square numbers");
    } ...
  2. do {...} while(...) loop:

      ...
    public static void doWhileSquareNumbers(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 thoroughly to avoid a common pitfall.

Which of these three loop implementations is your favourite? Give a reason.

A:

The while loop is actually quite straightforward to implement:

public class LoopExample {
  ...
  public static void whileSquareNumbers(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 doWhileSquareNumbers(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 is however flawed: If we call doWhileSquareNumbers(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 line of output is being printed contradicting the method's Javadoc. Avoiding this error requires the loop to be enclosed in an if- statement:

public static void doWhileSquareNumbers(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 if-clause reminds us that a do {...} while (...) is an ill-suited choice here: Both a while(...){...} or a for(...){...} loop avoid this problem in the first place rather than requiring its symptoms to be cured.

Actually a for(...){...} loop is our best choice here since:

  1. The number of iterations is known in advance.

  2. The increment is constant.

  3. It allows for prior initialization.

.