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
boolean
type;
if
and
switch
;
SimpleDate
object;
and
Your instructor will tell you which of the proposed experiments you are to perform.
Prerequisite skills:
Required files:
Optional applet files:
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.
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 ``is not'';
<
for ``is less than'';
<=
for ``is less than or equal to'';
>
for ``is greater than'';
and
>=
for ``is greater than or equal to''.
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.
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.
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 if
s, 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.
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.
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
Name: ________________
ID:_______________
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).
boolean
methodsRequired 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.
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)
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.
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.
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.
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?
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?
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?
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.
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.
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.
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
.
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.
isWinter
, revisited
Rewrite isWinter
so that it uses precedes
appropriately.
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
.
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.
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.
Create an applet that draws shapes (squares, circles, etc.) and that permits the HTML page to customize at least three aspects of the drawing.
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.).
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.
[Front Door] [Introduction] [Code]
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