Static Members

Figure 261. 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 the overall member count for every new member.

  • Instance level: Assign the current member count to each new instance.


Figure 262. Implementing membership numbers. Slide presentation Create comment in forum
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.

Whenever a new instance of ClubMember is being created two things happen:

  1. The overall memberCount variable is being incremented.

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

Accessing an instance's membership number.


Figure 263. Showing membership numbers. Slide presentation Create comment in forum
public static void main(String[] args) {

  final ClubMember john = new ClubMember("John"),
                  karen = new ClubMember("Karen");

    System.out.println(karen.getDetails());
}
Member Karen, member number 2

Figure 264. Access to 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 265. 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 266. Do we 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: Object state irrelevant.


Figure 267. 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 268. Syntax accessing class members Slide presentation Create comment in forum
Class Variable

{class name}.{variableName}

Class Method

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


exercise No. 92

Class vs. instance Create comment in forum

Q:

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

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

A:

  1. Adding the static modifier yields:

    public class ClubMember {
     ...
      final private int memberNumber;
      final private String name;
    ...
      static public String getDetails() {
        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
  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(karen.getDetails());
    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 does not depend on individual member instances.

exercise No. 93

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

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.