Experiments in Java


Session J4: Boolean Expressions and Conditionals

In this laboratory session, you will learn about conditional control structures, which permit your Java programs to select which actions to perform. You will learn about control structures as we develop a more useful SimpleDate class that permits us to represent and manipulate dates. The goals of this laboratory are to

Your instructor will tell you which of the proposed experiments you are to perform.

Prerequisite skills:

Required files:

Optional applet files:


Discussion

Let us turn our attention to the creation of a simple class to represent dates. We will call this class SimpleDate. You may have created such a class in a previous lab. In case you haven't (or in case you are not confident in your code), here is a sample one.


/**
 * A very simple implementation of dates using Gregorian-style 
 * calendars (with year, month, and day).
 *
 * @author Samuel A. Rebelsky
 * @version 1.2 of September 1998
 */
public class SimpleDate {

  // +--------+--------------------------------------------------
  // | Fields |
  // +--------+

  /** The year. */
  protected int year;

  /** The month.  Use 1 for January, 2 for February, ...  */
  protected int month;

  /** The day in the month.  */
  protected int day;


  // +--------------+--------------------------------------------
  // | Constructors |
  // +--------------+

  /**
   * Build a new date with year, month, and day.  The month should be
   * between 1 and 12 and the day between 1 and the number of days in
   * the month.
   */
  public SimpleDate(int y, int m, int d) {
    this.year = y;
    this.month = m;
    this.day = d;
  } // SimpleDate(int,int,int)


  // +------------+----------------------------------------------
  // | Extractors |
  // +------------+

  /**
   * Get the year.
   */
  public int getYear() {
    return this.year;
  } // getYear()

  /**
   * Get the month.
   */
  public int getMonth() {
    return this.month;
  } // getMonth()

  /**
   * Get the day.
   */
  public int getDay() {
    return this.day;
  } // getDay()

  /**
   * Convert to a string (American format: MM/DD/YYYY)
   */
  public String toString() {
    return this.month + "/" + this.day + "/" + this.year;
  } // toString()

} // class SimpleDate


At present, this class is relatively primitive. All we can do is create new dates, check on their various components, and convert dates to strings. Good object design dictates that we think about some other things we might want to do with dates, such as check whether the current year is a leap year or determine the number of days in the month.

In Experiment J4.1 you will extend this SimpleDate class.

Boolean expressions

While there are a number of different methods we might add to the SimpleDate class, we will begin with some relatively basic ones (in terms of the complexity of implementation) and move on to more complicated ones.

To begin with, we'll look at a very simple question: ``Does this date occur in January?'' While it is not a very sophisticated question, it will help us get started with more advanced questions. It might even be used in support of other questions. For example, in order to determine whether a date is in winter, we might want to check if it's in January.

How do we determine if the date occurs in January? Fairly easily: all we need to do is compare the month field to the value we use for January (1).

Now, how might we express this as a Java method? By this point, you should know that every method begins with the keyword public, a return type, a method name, and a parameter list. Each method also has a body that describes how to implement the method.

What name should we give our method that checks whether the current date falls in January? Perhaps inJanuary.

What type should inJanuary return? It shouldn't return a number, since numbers aren't used to answer questions like ``Is this day in January?'' (If you don't understand this, think about how you'd react to ``four'' as an answer to ``Is it sunny today?'') Strings seem like they might be appropriate, since "Yes" and "No" are valid responses. However, these are really the only responses that we would accept (e.g., "Zebra" is not a response we would be very happy with). Because there are many cases in which we accept only two answers, Java provides a primitive type, boolean, which only has two legal values. The two legal values are true (corresponding to ``yes'') and false (corresponding to ``no''). The type is named boolean after George Boole, a logician who developed a system of reasoning about these two values.

What parameters do we send to inJanuary? None, it turns out. While you may be tempted to give inJanuary a SimpleDate as a parameter, in the object-oriented perspective, we will ask each date whether it occurs in January. A small difference, but an important one.

Putting it all together, we get the following:

  /** 
   * Determine whether the current date falls in January.
   */
  public boolean inJanuary() {
    ...
  } // inJanuary()

If the month field has the value 1, then it is January. The ``is'' operator in Java is written == and, as you might guess, returns a boolean value. We write this as

    return this.month == 1;

In addition to == for ``is'', Java also supports

For example, you might check if x is negative with x<0. Similarly, you might check if x is non-negative with x>=0.

In Experiment J4.2 you will develop some simple boolean methods.

Operations on Booleans

As you might guess, we can be somewhat limited if all we can do is one comparison. In particular, you may want to use the results of a comparison and you may want to do multiple comparisons. We will examine the second issue first and write boolean expressions that involve multiple comparisons. In particular, we will look at three new questions we might ask about a date:

These questions have some other appropriate aspects. Our previous question (``Does this date occur in January?'') is at least partially involved in the answer to two of these questions (``Does this date occur in winter?'' and ``Is this date the first day of the year?''). The last two questions also have simple approximate answers (e.g., ``It's winter if it's December, January, or February'') and more complex correct answers (e.g., ``It's winter if it's after the winter solstice and before the vernal equinox''). Note also that these questions are used to answer more complex questions, like ``How many days are there in this year?'' and ``How likely is it to be cold on this day?''

How do we know that a day is the first day of the year? It's the first day of the year if it's in January and it's the first day of the month. You'll note that we have two tests we want, and we'd like both of them to hold. Just as we said and in the sentence above, we use an and operator in Java. Surprisingly, and is written && in Java. Using that operator, we can write

  /**
   * Is this day the first day of the year?
   */
   public boolean isFirstDay() {
     return (this.month == 1) && (this.day == 1);
   } // isFirstDay

Note that we could also have used inJanuary() in place of (this.month == 1). Note also that we used parentheses to gather together the subexpressions. Such parentheses aren't always necessary, but we recommend that you use them as they keep your code clearer.

Is isFirstDay strictly necessary? Probably not, as we could just use the test that forms the one line of its body. However, using isFirstDay can make our code more readable, shorter, and more supportive of change. For example, if it were somehow decreed that July 31 were the first day of the year, we would only need to change isFirstDay and not hundreds or thousands of lines of code.

Now let us move on to the next method. How do we determine if a date occurs in winter? We'll use the simple view that a month is in winter if it is in December, January, or February. Note that here we used the word or. Java includes an or operator that holds if either argument holds. In Java, or is written ||. Using that operator, we can write the simple isWinter as follows.

  /**
   * Is this day in winter?
   */
  public boolean isWinter() {
    return (this.month == 12) ||
           (this.month == 1) ||
           (this.month == 2);
  } // isWinter

You might want to think about how to write a more sophisticated version of this method that only returns true when it's between the winter solstice and the vernal equinox.

How do we determine whether it's a leap year? For the modern Gregorian calendar, it involves a relatively simple calculation. You might think that this calculation is ``a year is a leap year if the year is divisible by 4''. However, the designers of the Gregorian calendar realized that such a calculation would lead to some inaccuracy as the centuries marched on. In fact, years divisible by 100 are not leap years, unless they are also divisible by 400. So, 1900 is not a leap year, but 2000 is. Is such precision necessary in a computer program? Certainly. For example, computer programs are responsible for computing interest on bank accounts, and you wouldn't want the bank to pay you one less day of interest in some years (and, conversely, the bank wouldn't want to pay all of its customers for an extra day of interest). More importantly, if you claim that a leap year isn't a leap year, then you'll misidentify which day of the week most days of the year fall on. So, we can say that

a year is a leap year if is divisible by 400 or if it is divisible by 4 and not divisible by 100.

So, how do we determine if a year is evenly divisible by 4 (or 100 or 400). We can use the modulus or remainder operator, %. To express ``the remainder after dividing x by 4'' in Java, we would write x%4. A number is evenly divisible by 4 if the remainder after dividing by 4 is 0, hence year is divisible by 4 if (year%4 == 0).

Putting it all together, we get

  /**
   * Determine if the current year is a leap year.
   */
  public boolean isLeapYear() {
    return (this.year % 400 == 0) ||
      ((this.year % 4 == 0) && (this.year % 100 != 0))
  } // isLeapYear

Note that we used the ``is not'' operator, !=. We can also use the boolean not operator, which is written !. So, we could also write ``this year is not divisible by 100'' as

!(this.year % 100 == 0)

In Experiment J4.3 you will develop additional boolean methods for the SimpleDate class.

Conditionals

By this point, you may have noted that we are not doing much with the results of all the methods we have developed. If you have done the experiments, you will have noted that you can use them to print true or false, but not much else. So, how do we use boolean variables and methods? Most typically, we use them in conditional expressions. For example, if someone asked how many days there are in the year, you might say to yourself ``If it is a leap year, then there are 366 days; otherwise, there are 365 days''. Java provides an if statement that does something similar.

The if statement has the form

    if (condition) {
      statement-list;
    }
    else {
      statement-list;
    }

To execute an if statement, Java first evaluates the condition (a boolean expression). If the condition holds (evaluates to true), Java then executes the statements in the first statement list. If the condition does not hold, Java then executes the statements in the second list.

For example, to print meaningful text about whether or not a day falls in winter, we might write

    if (day.isWinter()) {
      out.println(day.toString + " falls in winter.");
    }
    else {
      out.println(day.toString + " does not fall in winter.");
    }

Similarly, to write a function that returns the number of days in the current year we might write

  /**
   * Determine the number of days in the current year.
   */
  public int daysInYear() {
    if (this.isLeapYear()) {
      return 366;
    }
    else {
      return 365;
    }
  } // daysInYear()

Note that you do not need to include the else portion of the if statement. If you leave out the else and the condition fails, Java simply goes on to the next statement. For example, if you only want to print a comment about winter days, you might write

    // Say something about cold winter days.
    if (day.isWinter()) {
      out.println("Brr ... I'll bet it's cold on " + 
                  day.toString() + ".");
    } // if the day is in winter

We are now ready to consider a more complicated method, one that determines whether or not the current date precedes another date. This method requires us to do a sequence of tests. One might say

Note that if we wrote this using the indentation method given above, we would indent fairly far. Hence, custom dictates that in a series of nested ifs, you maintain the same indentation, as in

  /** 
   * Determine if the current date precedes the parameter.
   */
  public boolean precedes(SimpleDate other) {
    if (this.year < other.year) {
       return true;
    }
    else if (this.year > other.year) {
     return false;
    }
    else if (this.month < other.month) {
      return true;
    }
    else if (this.month > other.month) {
      return false;
    }
    else if (this.day < other.day) {
      return true;
    }
    else if (this.day > other.day) {
      return false;
    }
    else {
      return false;
    }
  } // precedes(SimpleDate)

In Experiment J4.4 you will improve the output from this class. In Experiment J4.5 you will investigate comparison of dates.

The switch statement

Let us now consider how one might compute the number of days until the end of the month. If we had a daysInMonth function, we might simply write

  /**
   * Compute the number of days until the end of the month.
   */
  public int daysLeftInMonth() {
    return this.daysInMonth() - this.day;
  } // daysLeftInMonth()

If you've done Experiment J4.5, you may even have started to write such a method. However, we will assume that no such method is available. What should we do? It seems like a series of nested if statements is necessary, as in

  /**
   * Compute the number of days until the end of the month.  Return
   * -1 if it is not possible to determine this value.
   */
  public int daysLeftInMonth() {
    if (this.month == 1) {
      return 31 - this.day;
    } // January
    else if (this.month == 2) {
      if (this.isLeapYear()) {
        return 29 - this.day;
      } // A leap year
      else {
        return 28 - this.day;
      } // Not a leap year
    } // February
    
    ...
    
    else if (this.month == 11) {
      return 30 - this.day;
    } // November
    else if (this.month == 12) {
      return 30 - this.day;
    } // December
    else { // Aagh!  Not a month I recognize.
      return -1;
    } // Troubles
  } // daysLeftInMonth()

Such a solution is rather cumbersome. To handle some of these cumbersome cases, Java provides the switch statement, which has the following form

    switch (expression) {
      case val-1: 
        statement-list-1;
        break;
      case val-2:
        statement-list-2;
        break;
      ...
      case val-n:
        statement-list-n;
        break;
      default:
        statement-list;
        break;
    } // switch

This statement has the meaning ``Evaluate the expression. If it is equal to val-1, then execute statement-list-1. Otherwise, if it is equal to val-2, then execute statement-list-2. If the expression is not equal to any of the values, execute the default statement list.''

Using this statement, we can rewrite daysLeftInMonth as

  /**
   * Compute the number of days until the end of the month.  Return
   * -1 if it is not possible to determine this value.
   */
  public int daysLeftInMonth() {
    int daysLeft;
    switch (this.month) {
      case 1:  // January
        daysLeft = 31 - this.day;
        break;
      case 2:  // February
        if (this.isLeapYear()) {
          daysLeft = 29 - this.day;
        } 
        else {
          daysLeft = 28 - this.day;
        }
        break;
    ...
    
      case 12:  // December
        daysLeft = 31 - this.day;
        break;
      default:
        daysLeft = -1;
        break;
    } // switch(this.month)
    return daysLeft;
  } // daysLeftInMonth()

Note that you can only use switch statements with primitive types, like integers, boolean values, and real numbers.

It is possible to use multiple labels (the lines that read case) for each statement sequence. If any of the corresponding values match, then the statement is executed. Using this feature, we can rewrite daysLeftInMonth a final time.

  /**
   * Compute the number of days until the end of the month.  Return
   * -1 if it is not possible to determine this value.
   */
  public int daysLeftInMonth() {
    int daysLeft;
    switch (this.month) {
      case 1:  // January
      case 3:  // March
      case 5:  // May
      case 7:  // July
      case 8:  // August
      case 10: // October
      case 12: // December
        daysLeft = 31 - this.day;
        break;
      case 4:  // April
      case 6:  // June
      case 9:  // September
      case 11: // November
        daysLeft = 30 - this.day;
        break;
      case 2:  // February
        if (this.isLeapYear()) {
          daysLeft = 29 - this.day;
        } 
        else {
          daysLeft = 28 - this.day;
        }
        break;
      default:
        daysLeft = -1;
        break;
    } // switch(this.month)
    return daysLeft;
  } // daysLeftInMonth()

We will not cover many subtleties to the switch statement. For example, you can leave out the break statements, in which case you ``fall through'' to the next bit of code.

In Experiment J4.6 you will investigate the switch statement.

Applet parameters

This section is optional and is intended for classes emphasizing applets or pursuing a simultaneous discussion of applications and applets.

As you may have noticed, the applets that we've built so far are limited. If you want an applet to do something slightly different (e.g., display a different piece of text), you need to change the source code of the applet. Is this the only way to configure an applet? No. You can also use the HTML page to set other attributes of the applet. These are often called the applet's parameters. What can the parameters be? Anything you think is appropriate: colors, text, more general instructions, and so on and so forth.

How do you set a parameter? With a param tag (another HTML tag). The param tag goes between your applet tags. For example, to indicate that the message should be ``Reconfigured'', one might write:

<param name="message" value="Reconfigured">

How can you access that parameter? With a getParameter method. The getParameter method always returns a string (even if you want a number). If the HTML code does not include a param tag with the appropriate name, getParameter returns the special null value.

Here is the paint method of a simple applet that draws a selected string in green.

  public void paint(Graphics paintBrush) {
    String msg;
    msg = getParameter("message");
    paintBrush.setColor(Color.green);
    paintBrush.drawString(msg, 10, 14);
  } // paint(Graphics)

If the message parameter is set to ``Hello World'', then this will display ``Hello World''. If the message parameter is set to ``Java Rules'', then this will display ``Java Rules''.

But what if the page does not set a parameter? Then msg will by null. We don't know what drawString does with null messages, but it's unlikely to be pleasant. Hence, we should specify a default message that the applet uses when no parameter is supplied. How do we know when to use the default? Conditionals help us tell.

    String msg = getParameter("message");
    if (msg == null) {
      msg = "No message selected";
    }

Conditionals can also help you help you convert strings to other objects. As an example of conversion, consider how one might allow the Web page to set the color that text is displayed in. As before, getParameter will return a string. Presumably, the string for the color will be ``blue'', ``red'', ``yellow'', or other colors you wish to support. Yet setColor needs a color. Hence, we compare the string for the color to members of a fixed set of strings, and when we find which it matches, we select the appropriate color. For example,

    Color color = Color.black;	// Default
    String colorName = getParameter("color");
    if ("blue".equals(colorName)) { color = Color.blue; }
    else if ("red".equals(colorName)) { color = Color.red; }
    else if ("yellow".equals(colorName)) { color = Color.yellow; }

Note that we compare strings with the equals method rather than ==.

What about numeric parameters? Since your applet receives the parameter as a string, you need a way to convert strings to numbers. Unfortunately, while Java includes a standard conversion mechanism, that mechanism is somewhat confusing for novices. Conversion involves the use of the Integer.parseInt method along with a try/catch clause. For example,

    int fontSize;
    String sizeParam = getParameter("Size"); 
    try { 
      fontSize = Integer.parseInt(sizeParam);
    }
    catch (Exception e) {
      fontSize = 12;
    }

What does this say? As you might guess, the first line is a declaration of the variable fontSize and the second line reads in the string used for the font size. The line that reads fontSize = Integer.parseInt(sizeParam); does the conversion.

So, what is a try/catch clause? It's a kind of conditional. Java cannot convert all strings to integers. For example, what integer should it use for the string "Hello"? Hence, you'd like to write a conditional that says something like ``if the conversion fails, use a default''. The try indicates that you're doing something that might fail. The catch is the ``if it fails, do this''.

In effect, the code above says ``try to convert sizeParam to an integer and then assign it to fontSize; if that fails, assign 12 to fontSize''.

In a subsequent lab, you will consider try/catch clauses in more depth. For now, just model your code on this example. You are now ready to build parameterized applets. In Experiment J4.7 you will consider the basics of applet parameters. In Experiment J4.8 you will use conditionals to improve applet customization.

In both labs, you will use and extend the following customizable applet.


import java.applet.Applet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;

/**
 * A simple illustration of applet parameters.
 * Will eventually support the following parameters:
 *   message: the message to print
 *   font: the base font (Serif, SansSerif, etc.)
 *   size: the size of the font
 *   style: the style (plain, bold, italic, bolditalic)
 *   color: the color of the message
 *   shadow: the color of a shadow behind the message
 * The initial version supports only the message parameter.
 *
 * @author Samuel A. Rebelsky
 * @version 1.0 of August 1999
 */
public class ConfigurableGreeting 
  extends Applet
{
  /** Paint the greeting. */
  public void paint(Graphics paintBrush) {
    // Begin with reasonable defaults
    String message = "A configurable message";
    String fontName = "Serif";
    int fontSize = 14;
    int fontStyle = Font.PLAIN;
    Color fontColor = Color.red;
    Color shadowColor = Color.gray;

    // Read information from the parameters.
    message = getParameter("message");
    
    // Set the font in preparation for writing.
    paintBrush.setFont(new Font(fontName, fontStyle, fontSize));

    // Paint the shadow first.  The vertical offset is based on 
    // the size of the font.  This allows the message to appear
    // at the top of the applet. 
    paintBrush.setColor(shadowColor);
    paintBrush.drawString(message, 12, fontSize+6);

    // Paint the message.
    paintBrush.setColor(fontColor);
    paintBrush.drawString(message, 10, fontSize+4);
  } // paint(Graphics)
} // class ConfigurableGreeting



Experiments

Name: ________________
ID:_______________

Experiment J4.1: Extending the SimpleDate class

Step 1. Make a list of at least three capabilities you might want to include in the SimpleDate class. You might consider changing dates, getting other types of information about dates, or working with multiple dates.


 
 
 
 
 
 

Step 2. Express each of the capabilities described in Step 1 as a Java method. For each method, you need only provide type, name, and parameters. You need not provide any code in the bodies of the methods (in fact, it is the purpose of this lab to help you develop these bodies).


 
 
 
 
 
 

Experiment J4.2: Simple boolean methods

Required files:

Step 1. Make copies of SimpleDate.java and DateTester.java. Compile both files and execute DateTester. Record the results.


 
 
 
 
 
 

Step 2. Add the inJanuary method to the SimpleDate class. Here is the code for that method.

  /** 
   * Determine whether the current date falls in January.
   */
  public boolean inJanuary() {
    return this.month == 1;
  } // inJanuary()

Update DateTester to print out whether each day is in January with

    out.println("Is " + day_one.toString() + " in January? " +
                day_one.inJanuary());

Recompile both files and execute DateTester. Record the new results.


 
 
 
 
 
 

Step 3. Add an isAugust method to the SimpleDate class. You will need to write this method yourself. Update DateTester to print out whether each day is in August. Enter the code for your new method here.


 
 
 
 
 
 

Step 4. Add an inFirstHalf method to the SimpleDate class. This method should test whether a date falls in the first half of the year (in any month through June). You can assume that the month field contains a number between 1 and 12. Recompile and test your method until you are confident that it works. Enter the method, the test code, and the output here.


 
 
 
 
 
 
 
 
 
 
 
 
 
 

Experiment J4.3: More boolean methods

Step 1. Add the isFirstDay method to the SimpleDate class. Update DateTester to use that method. Add a few more dates to DateTester to make sure that your testing is more comprehensive. Recompile the files and execute DateTester. Record the results here.


 
 
 
 
 
 

Step 2. Add the isWinter method to the SimpleDate class. Update DateTester to test that method (perhaps adding more dates if appropriate). Recompile the files and execute DateTester. Record the results here.


 
 
 
 
 
 

Step 3. Update the isWinter method so that it correctly (rather than approximately) answers the question ``Is it winter?'' In particular, your method should only claim that days on or after the winter solstice but before the vernal equinox are in winter. Record your code for isWinter here.


 
 
 
 
 
 
 
 
 
 
 
 
 
 

Step 4. Run DateTester. Note that you should not need to make any changes to DateTester. Record your results here.


 
 
 
 
 
 

Step 5. Finish the equals method begun below. This method should return true if the parameter is equal to the current date and false otherwise.

  /**
   * Determine whether the parameter is the same as this date.
   */
  public boolean equals(SimpleDate d) {
    
    
    
  } // equals(SimpleDate)

Experiment J4.4: Improved output

Step 1. Update DateTester so that for each sample date it prints

Brr ... the date falls in winter.

for dates that fall in winter and

Fortunately, the date does not fall in winter.

for those dates that do not fall in winter. Summarize your code here.


 
 
 
 
 
 

Step 2. Update DateTester so that for each sample date it prints

It seems that the date falls in the first half of the year.

for dates that do just that. It should not print anything for other dates. Summarize your code here.


 
 
 
 
 
 

Experiment J4.5: More fun with conditionals

Step 1. Add the precedes method to the SimpleDate class. Update DateTester to check at least three interesting pairs of dates and print appropriate messages concerning their relative appearance in the year. Record your output here.


 
 
 
 
 
 

Step 2. Write a daysInMonth method that returns the number of days in the current month. For now, your method need only work for dates in January, February, and March (return some default value for every other date). Summarize your code here.


 
 
 
 
 
 
 
 
 
 
 
 
 
 

Step 3.

Update DateTester to test the daysInMonth method. Summarize the test and enter the output here.


 
 
 

Step 4.

Write a new constructor,

  public SimpleDate(int y, String m, int d)

that allows one to create a new date by using an appropriate string for the month (e.g., March). Note that to compare two strings, you need to use the equals method, as in

    if (s1.equals(s2)) {
      out.println("'" + s1 + "' is the same as '" + s2 + "'");
    }

Your constructor need only work with the months January, February, and March, although it should support both the full names of the months and the abbreviated versions. Summarize your code here.


 
 
 
 
 
 
 
 
 
 
 
 
 
 

Experiment J4.6: Using the switch statement

Step 1. Using a switch statement, write a daysInMonth method that returns the number of days in the current month. Summarize the code for the method here.


 
 
 
 
 
 
 
 
 
 
 
 
 
 

Step 2. Update DateTester to test the daysInMonth method. Enter the output here.


 
 
 
 
 
 

Step 3. Using your daysInMonth method from Step 1 above, write a daysLeftInMonth method. Update DateTester to test this new method. Enter the output here.


 
 
 
 
 
 

Step 4. Using a switch statement, write a new constructor,

  public SimpleDate(int y, String m, int d)

that allows one to create a new date by using an appropriate string for the month (e.g., March). Test your constructor. Does it seem to do what you expect? Why or why not?


 
 
 
 
 
 

When you have answered this question, you may wish to read the notes on this step.

Experiment J4.7: Applet parameters

Required files:

Step 1. Make copies of ConfigurableGreeting.java and greeting.html. Consider the code for ConfigurableGreeting.java. Explain, in your own words, what each part of the paint method does.


 
 
 
 
 
 

Step 2. Look at greeting.html. What message do you expect this page will display?


 
 
 

Step 3. Compile ConfigurableGreeting and load the applet with greeting.html. Describe the output.


 
 
 

Step 4. Change the line in greeting.html that reads

    <param name="message" value="A Configurable Applet">

to instead read

    <param name="message" value="Reconfigured">

What do you expect to happen if you load the applet using the modified greeting.html? Note that you have not recompiled ConfigurableGreeting.


 
 
 

Load the applet using greeting.html to confirm your answer.

Step 5. Change the line in greeting.html that reads

    <param name="message" value="Reconfigured">

to read

    <param name="MESSage" value="Reconfigured">

That is, change the capitalization of message. What effect do you expect this change to have?


 
 
 

Step 6. Load the applet using greeting.html to confirm your answer. You may also wish to consult the notes on this step.

Change the line in ConfigurableGreeting.java that reads

    message = getParameter("message");

to instead read

    message = getParameter("MESSAGE");

That is, change the capitalization of message. What effect do you expect this change to have?

Recompile ConfigurableGreeting and then load the applet using greeting.html to confirm your answer. You may also wish to consult the notes on this step.


 
 
 

Step 7. Change the line in greeting.html that reads

    <param name="MESSage" value="Reconfigured">

to read

    <param name="greeting" value="Reconfigured">

Change the line in ConfigurableGreeting.java that reads

    message = getParameter("MESSAGE");

to read

    message = getParameter("greeting");

What effect do you expect these changes to have?


 
 
 

Recompile ConfigurableGreeting and then load the applet using greeting.html to confirm your answer. You may also wish to consult the notes on this step.

Step 8. Change the line in greeting.html that reads

    <param name="greeting" value="Reconfigured">

to again read

    <param name="message" value="Reconfigured">

Do not change ReconfigurableGreeting. What effect do you expect the change to greeting.html to have?


 
 
 

Load the applet using greeting.html to confirm your answer. You may also wish to consult the notes on this step.

Step 9. As you may have observed, the difficulty here is that the HTML file no longer contains a greeting parameter. Good programming style dictates that our applet have a default message. Change the line in ReconfigurableGreeting that reads

    message = getParameter("greeting");

to read

    message = getParameter("greeting");
    if (message == null) {
      message = "No message specified.";
    }

What effect do you expect this change to have?


 
 
 

Recompile ConfigurableGreeting and then load the applet using greeting.html to confirm your answer.

Step 10. What changes would we need to make to ConfigurableGreeting in order to support a font parameter? Do not make the changes, just summarize them.


 
 
 
 
 
 

Step 11. Add a line to greeting.html that reads

    <param name="font" value="SansSerif">

What effect do you expect this line to have?


 
 
 

Step 12. Add the following line to the paint method of ConfigurableGreeting.

    fontName = getParameter("font");

This should follow the steps used to get the message and precede the call to setFont. What effect do you expect this change to have?


 
 
 

Confirm your answer by recompiling ConfigurableGreeting and then loading the applet with the modified greeting.html.

Step 13. Replace the line in greeting.html that reads

    <param name="font" value="SansSerif">

with

    <param name="font" value="Monospaced">

What effect do you expect this change to have?


 
 
 

Step 14. Replace the line in greeting.html that reads

    <param name="font" value="Monospaced">

with

    <param name="font" value="NoSuchFont">

What effect do you expect this change to have?


 
 
 

Step 15. For a robust applet, the one line added in step 12 is not enough. Why not? What other lines should we also include?


 
 
 
 
 
 

Experiment J4.8: More applet parameters

Required files:

Before you begin, if you have not already done so, make copies of ConfigurableGreeting.java and greeting.html. Make sure that you understand the code in ConfigurableGreeting.java.

Step 1. Add the following lines to greeting.html within the applet tags.

    <param name="size" value="24">
    <param name="style" value="bold">
    <param name="color" value="white">
    <param name="shadow" value="black">

What effect do you expect these changes to have?


 
 
 

After recording your answer, you may wish to consult the notes on this step.

Step 2. Add the following lines to the paint method of ConfigurableGreeting. They should fall after the other calls to getParameter, but before the calls to setFont and setColor.

    String colorName = getParameter("color");
    if ("black".equals(colorName)) { fontColor = Color.black; }
    else if ("blue".equals(colorName)) { fontColor = Color.blue; }
    else if ("green".equals(colorName)) { fontColor = Color.green; }
    else if ("purple".equals(colorName)) { fontColor = new Color(255,0,255); }
    else if ("red".equals(colorName)) { fontColor = Color.red; }
    else if ("white".equals(colorName)) { fontColor = Color.white; }
    else if ("yellow".equals(colorName)) { fontColor = Color.yellow; }

What effect do you expect these new lines to have?


 
 
 

Confirm your answer by recompiling ConfigurableGreeting and loading the applet from greeting.html.

Step 3. Replace the line in greeting.html that reads

    <param name="color" value="white">

with one that reads

    <param name="color" value="yellow">

Do not recompile ConfigurableGreeting. What effect do you expect this change to have?


 
 
 

Confirm your answer by loading the applet from greeting.html.

Step 4. Replace the line in greeting.html that reads

    <param name="color" value="yellow">

with one that reads

    <param name="color" value="WHITE">

Do not recompile ConfigurableGreeting. Load the applet from greeting.html. What color does the text appear in? Why?


 
 
 

After recording your answer, you may wish to consult the notes on this step.

Step 5. Update ConfigurableGreeting so that it also reads the color of the shadow from the HTML file. Summarize your changes here.


 
 
 
 
 
 

Step 6. Update ConfigurableGreeting so that it also reads the font style from the HTML file. Summarize your changes here.


 
 
 
 
 
 

Step 7. Add the following lines to the paint method of ConfigurableGreeting. They should fall after the other calls to getParameter, but before the calls to setFont and setColor.

    String sizeParam = getParameter("Size");
    try {
      fontSize = Integer.parseInt(sizeParam);
    }
    catch (Exception e) {
      fontSize = 12;
    }

Recompile ConfigurableGreeting and load the applet from greeting.html. What effect did this new code have?


 
 
 

Step 8. Replace the lines added in step 7 with the following two lines.

    String sizeParam = getParameter("size");
    fontSize = Integer.parseInt(sizeParam);

Recompile ConfigurableGreeting and load the applet from greeting.html. What effect did this new code have?


 
 
 

Step 9. It seems that it's just as easy to use the shorter code from step 8 rather than the longer code from step 7. However, this isn't always so. Try replacing the line in greeting.html that sets the font size with

    <param name="size" value="twenty">

Load the applet from greeting.html. What happens?


 
 
 

Step 10. Replace the two lines inserted in step 8 with the longer code from step 8. Recompile ConfigurableGreeting. Load the applet from greeting.html. What happens? What does that suggest about the try/catch clause?


 
 
 

After recording your answer, you may wish to consult the notes on this step.

Step 11. Replace the line in greeting.html that reads

    <param name="size" value="twenty">

with one that reads

    <param name="size" value="32">

What effect does this have?


 
 
 


Post-Laboratory Problems

Problem J4-A: Rethinking precedes

It is possible to write precedes without any if statements. How? By using a complex boolean expression. Write precedes so that it has only one line, a return of an appropriate boolean expression. Make sure to test your method.

Which version of precedes do you prefer? Why?

Problem J4-B: Incrementing a date

Write and test a method, SimpleDate tomorrow(), that returns the day after the current date. For example, if d is August 29, 1987, then d.tomorrow() should be August 30, 1987. If d is July 31, 1995, then d.tomorrow() should be August 1, 1995.

Problem J4-C: Is the date valid?

Write and test a method, isValid, that returns true if the current date is legal and false otherwise. A date is legal if the month is legal and the day is at least one and no more than the number of days in that month.

Problem J4-D: Correcting dates

Write and test a method, void correct, that corrects an invalid date by advancing or backing up the appropriate amount. For example, the 14th month of 1964 should be the second month of 1965, the 0th month of 1931 should be the 12th month of 1930, the 32nd day of June should be the 2nd day of July, the 62nd day of June should be the 1st day of August, and the -4th day of December should be the 26th day of November.

Problem J4-E: Printing dates, revisited

Write and test a method, String toLongString, that returns the string corresponding to the longer version of the date. For example, for the date 12/3/1964 (in U.S. format), it might return December 3, 1964.

Problem J4-F: Printing dates, revisited again

Add a method, setPrintFormat, to SimpleDate. This new method should allow the user to select which date format (U.S. short, U.S. long, European short, etc.) to use. Update toString to check which format it should use.

Problem J4-G: isWinter, revisited

Rewrite isWinter so that it uses precedes appropriately.

Problem J4-H: Selecting colors, revisited

In Experiment J4.8, you found that Java's string comparison is case-sensitive, so "white" and "WHITE" are treated as different strings. Update the ConfigurableGreeting applet so that it is case-insensitive.

Hint: Look at the documentation for the methods provided by java.lang.String.

Problem J4-I: Selecting colors, revisited again

Update ConfigurableGreeting to support another dozen or so colors (of your choice). These colors should be available for both the message and the shadow.

Note: You may find it helpful to create a method that converts strings to colors.

Problem J4-J: Multiple greetings

Update ConfigurableGreeting so that it prints up to three messages, one per line. The applet parameters should be named firstMessage, secondMessage, and thirdMessage. Each will appear in the same font and color. If any of the three messages is missing, you should skip it.

Note: you'll need to take the font size into account when displaying one message per line.

Problem J4-K: Parameterized drawings

Create an applet that draws shapes (squares, circles, etc.) and that permits the HTML page to customize at least three aspects of the drawing.

Problem J4-L: Stick figures

Create a StickFigure applet that permits the HTML page to customize at least three aspects of the stick figure (arm length, shirt color, hat size, etc.).


Notes

Experiment J4.6, Step 4. It is likely that you failed in your attempt. Java only lets you switch on selected primitive types, and not on strings and other objects.

Experiment J4.7, Step 5. Hopefully, you've observed that the capitalization used within the param tag does not affect the passing of the parameter to the applet. In fact, the Java specification says that parameters are case-insensitive.

Experiment J4.7, Step 6. Hopefully, you've observed that the capitalization of the string used with getParameter tag does not affect the passing of the parameter to the applet. In both cases (param tag and getParameter), the Java specification says that parameters are case-insensitive.

Experiment J4.7, Step 7. It may seem confusing that the parameter is called greeting in the HTML file, but is stored in the variable message within the applet. However, Java does not require you to use the same name for the variable that stores a parameter that you've used for naming the parameter. We'll take advantage of this ability to choose a different internal name in the next experiment.

Experiment J4.7, Step 8. As you may have surmised, there is no longer a parameter tag for the greeting parameter that the applet expects. Hence, the call getParameter("greeting") returns null. The drawString method is unhappy with the null string and gives an error.

Experiment J4.8, Step 1. Since the applet does not yet read these new parameters, they have no effect.

Experiment J4.8, Step 4. While the name of the parameter is case-insensitive, the value of the parameter is case-sensitive. Java treats "white" and "WHITE" as different strings. Hence, none of the strings match the applet never changes fontColor from Color.red (which it was set to at the start of the paint method).

Experiment J4.8, Step 10. As suggested earlier, the try/catch permits us to specify a default value. More imporantly, it stops the program from reporting an error when we use values that Java does not know how to convert.


Copyright (c) 1998 Samuel A. Rebelsky. All rights reserved.

Source text last modified Wed Oct 6 12:40:51 1999.

This page generated on Tue Oct 26 15:39:41 1999 by Siteweaver.

Contact our webmaster at rebelsky@math.grin.edu