Radford University ITEC

ITEC120-ibarland (incl. office hrs)infolectureslabshws

Constructors deconstructed; Boolean expressions

public, private

(Oct.02 (Mon))

In lab, we saw code a method public String toString() (for each of class Die, class Player), and we said that public meant that any other object can walk up to a Die and ask it to convert itself toString. If a method or field is declared as private, then other classes cannot use it.
[Demo, making the fields of Die private. What about the random-number generator randy, should we provide getter/setter? Should randy even be mentioned in toString? What about the access privilege for setFace?]

From now on: Make all fields private (always), and all methods public (for now). You only need to provide getters and setters for fields you want other classes to be able to get/set. Within the class itself, you can just refer to the field itself.

Constructors, deconstructed

What exactly1 happens, when you call a constructor, like new Blarg()?

  1. Java makes a new Blarg with all of its fields set to a 0ish value (0.0 for float, false for bool, ).
    Note that even if you want some field to have the value 0 initially, you should set it yourself explicitly, so others reading your code know what you really intended, and don't have to guess whether you have a bug of uninitialized variables. (In fact, Java requires this, for constructors. There are other situations (creating arrays) when you don't absolutely need to initialize variables, but it's still something you should do.)
  2. Java looks at your class file, from top-to-bottom, and every time it sees a declared (non-static) field which you had initialized, it gives that value to the field.
  3. Then, Java runs the constructor code, starting from its first line.
If Java can't guarantee in advance that you'll have provided an initial field for every field, you'll get a compile-time eror.

Constructors rarely do anything interesting, besides accept some values which (almost always) are directly put into fields. Note that there are two common naming conventions: You can use parameter names which start with underscores (but otherwise have the meaningful name corresponding to the field):

class Blarg {
  int blargNum;
  String blargName;
  double blargDub = Double.MIN_VALUE:
  bool   blargTF;
  
  /**
   * Construct a Blarg, given
   */
  Blarg( int _blargNum, String _blargName ) {
    blargNum = _blargNum;
    blargName = _blargName;
    blargTF = false;        // This initial value might be provided when 
                            //   the field was declared, as with blargDub.
    }
Or, you can use the same suggestive name as the field name. But then it's tricky -- what does the name refer to, the parameter or the field? The answer is, the parameter, but we can use the keyword this to access a field directly.
class Blarg {
  int blargNum;
  String blargName;
  double blargDub = Double.MIN_VALUE:
  bool   blargTF;
  
  /**
   * Construct a Blarg, given
   */
  Blarg( int blargNum, String blargName ) {
    this.blargNum = blargNum;
    this.blargName = blargName;
    this.blargTF = false;       // This initial value might be provided when 
                                //   the field was declared, as with blargDub.
    }
(Just as you can walk up to an object and call a method using a dot, you can walk up to an object and set any field you have accesss to. So this.blargNum = just says “walk up to ourselves, and and set the field blargNum”. Since we have access to our own fields (even if they're private to others), this is okay.

Beware calling methods from constructors

While it's possible to call a method (in the same class) from a constructor, you should be very careful about doing this: People writing the other methods always assume the object being worked with (this) is in a valid, fully-initialized state. But if you call it from the middle of a constructor, you're only half initialized! Even getters and setters should be avoided in this situation. If you have code which needs to be done both in the constructor and in regular methods, then you'll have to be creative2. Fortunately, this situation doesn't arise often, as constructors usually just initialize fields more-or-less directly from their parameters.

Exam review

(Oct.03 (Tue))

I'll put out a drill-homework as extra credit; it will feature series of questions, all of the form:

Boolean expressions

(Oct.04 (Wed))

Read in book, Chapter 5: The type boolean is much simpler than (say) int, because rather than 4+ billion ints, there are only two boolean values: true, and false. Note that these two names aren't variables; they're values, just like 17 and -34 are.

There are some functions in Java which take two numbers, and return a boolean: >, >=, ==, !=, etc..

There is only one built-in Java statement which really uses booleans: that's the if-else statement. Syntax:

if (condition) {
  statements…
  } 
else {
  statements…
  }
Example: Back in lab-week02, we wrote inventoryMessage,
/**
 * @param animalType The type of animal (e.g. "newt")
 * @param numInStock The number of the given animal in stock.
 * @return A complete sentence describing the inventory
 * For example:
 * inventoryMessage( "dog", 3 ) = "There are 3 dogs in stock."
 */
String inventoryMessage( String animalType, int numInStock ) {
  return   "There are "
         + numInStock
         + animalType + "s"
         + " in stock.";
  }
How do we write this so that if there is exactly one in stock, then we don't get the “s” added to the end of the animal type?
  /**
   * @param animalType The type of animal (e.g. "newt")
   * @param numInStock The number of the given animal in stock.
   * @return A complete sentence describing the inventory
   * For example:
   * inventoryMessage( "dog", 3 ) = "There are 3 dogs in stock."
   */
  String inventoryMessage( String animalType, int numInStock ) {
    String answer;
    
    if (numInStock == 1) {
      answer =   "There is "
                + numInStock
                + " "
                + animalType
                + " in stock.";
      }
    else {
      answer =   "There are "
                + numInStock
                + " "
                + animalType + "s"
                + " in stock.";
      }
      
    return answer;
    }
Ech! It works, but it has repeated code. In particular -- if you later realize that (say) you forgot a space somewhere in the message, you might fix the code in place but forget to update the other copy. Or, your boss decides that the message should read something like “There are 5 beautiful rhinos in stock”, then you again need to remember to update multiple places in the code.

We can do better: Where do the two solutions differ? In only two places: “is” vs. “are”, and the suffix “s” vs. no suffix at all. We can factor out the common code, and let our if statement focus on just those differences:

  /**
   * @param animalType The type of animal (e.g. "newt")
   * @param numInStock The number of the given animal in stock.
   * @return A complete sentence describing the inventory
   * For example:
   * inventoryMessage( "dog", 3 ) = "There are 3 dogs in stock."
   */
  String inventoryMessage( String animalType, int numInStock ) {
    String verbForm;   // The correct verb for our result.
    String plurality;  // The noun-suffix, correctly plural or singular.
    
    if (numInStock == 1) {
      verbForm = "is";
      plurality = "";
      }
    else {
      verbForm = "are";
      plurality = "s";
      }

    return   "There " + verbForm + " "
             + numInStock
             + " "
             + animalType + plurality
             + " in stock.";
    }
One note: in our return statement, we had to add a + " " after verbForm. Should we just have had verbForm include a trailing space, assigning it to either "is " and "are "? Discuss.

Another example:

In your book's reading of Chpt.5, you saw that

  1. you can omit the else, if the curly-brackets would be empty:
      /**
       * @param animalType The type of animal (e.g. "newt")
       * @param numInStock The number of the given animal in stock.
       * @return A complete sentence describing the inventory
       * For example:
       * inventoryMessage( "dog", 3 ) = "There are 3 dogs in stock."
       */
      String inventoryMessage( String animalType, int numInStock ) {
        String verbForm  = "is"; // The correct verb for our result.
        String plurality = "";   // The noun-suffix, correctly plural or singular.
        
        if (numInStock != 1) {
          verbForm = "are";
          plurality = "s";
          }
    
        return   "There " + verbForm + " "
                 + numInStock
                 + " "
                 + animalType + plurality
                 + " in stock.";
        }
    
  2. When there is only a single statement in the body, the book reveals that you can conceivably omit the curly-brackets. 3 This is bad for several reasons:
    1. It's fairly common that you decide later to go back and add something to the if- or else- case, and you end up adding the brackets later. Moreover, if you have several lines in a block and delete them down to just one, you'd want to delete the brackets to be consistent (and not cause readers to wonder if there is some unintentional bug).
    2. This usually leads to confusion though, and the book has to spend several minutes talking about dangling elses.
    3. Consider:
         if (numInStock == 1)
           verbForm = "is";
         else
           verbForm = "are";
         
      What if we go back, and decide to add the lines for plurality, but we forget to put in curly-braces?:
         if (numInStock == 1)
           verbForm = "is";
           plurality = "";    // DANGER, WILL ROBINSON!
         else
           verbForm = "are";
           plurality = "s";
         
      Java gives an error “else without an if” -- why? If we hadn't had any else statement at all, would we have caught our error?
Upshot: Even if you have only one line in an if- or else- block, include curly-braces.
Two exceptions:

/** Return a greeting, selected randomly from a list of four greetings.
 * @return A greeting (randomly selected, not necessarily uniformly).
 */
public static String greet() {
  int choice = (new java.util.Random()).nextInt(100);
  
  if (choice < 30) {
    return "Hello.";
    }
  else if (choice < 33) {  
    return "Aloha.";
    }
  else if (choice < 50) {  
    return "Buenos dias, amigo/amiga.";
    }
  else if (choice < 99) {  
    return "Yo.";
    }
  else if (choice < 100) {  
    // Not an advisable greeting.  Use sparingly.
    return "System dot out dot println open \"hello\" close.";
    }
  

  String warning = "*** This line of code is unreachable! ***";
  }
Some discussions:

connectives

These were introduced in lab-week07.

1 Well, this isn't the whole story, as we ignore initialization blocks, as well as not mention static (class) initializon nor superclass constructors.      back

2 Probably, your best solution is to create a static (presumably private) method which does that common code, and invoke that method by explicitly passing this as an argument. The documentation for that static method should clearly state that this method is called from the constructor, and specify which parts of the object must be initialized to call it.      back

3So really, the actual syntax for Java's if-else statement is

if (statement)
  expression
else
  expression
This is actually a general case of the version-with-brackets, given in these notes. Why? Because along with assignment statments and return statements and if statements, there is a block statement, which looks like { statements… }.      back

ITEC120-ibarland (incl. office hrs)infolectureslabshws


©2006, Ian Barland, Radford University
Last modified 2006.Nov.09 (Thu)
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Powered by PLT Scheme