Java Newsletter by Glen McCluskey - Issue 10
Issue #010
October, 1996
Contents
- The Finally Clause and Method Exiting
- Comparing C/C++ and Java Part 10 - Labelled Break and Continue
- Performance - Garbage Collection and Setting to Null
- Newsletter Writing
- Introduction to Applet Programming Part 6 - Text Fields
REVIEWERS NEEDED
I am looking for a couple of additional people to help review this newsletter. If you are a reviewer, you receive the issue a few days early, and send me your comments. The present set of reviewers have done much to improve the quality of the newsletter. If you have Java experience and are interested in this, please send me a note (glenm@glenmccl.com).
THE FINALLY CLAUSE AND METHOD EXITING
Java has no "goto" statement, though this identifier is reserved in the language. There are several ways in which goto is used in C and C++, and it's interesting to consider the Java alternatives to such usage. In this section we will discuss one alternative, and in the next section another.
One way that goto is used is to jump to the end of a function body, where cleanup can be done. For example, suppose that we are manipulating calendar dates, and have a function where we want a year in the range 1900-99 and evenly divisible by 4. In C, we might have:
void f(int d)
{
if (d < 1900)
goto err;
if (d > 1999)
goto err;
if (d % 4)
goto err;
/* do stuff with date ... */
return;
err:
fprintf(stderr, "invalid date %d\n", d);
}
In Java, we can achieve a similar end without goto, by using a form of the try-catch-finally statement used in exception handling:
public class test {
public static void f(int d)
{
boolean err = true;
try {
if (d < 1900)
return;
if (d > 1999)
return;
if (d % 4 != 0)
return;
err = false;
// do stuff with date ...
}
finally {
if (err)
System.err.println("invalid date "
+ d);
}
}
public static void main(String args[])
{
f(1852);
f(1976);
f(1989);
}
}
The code within the try block is "tried", that is, executed. After the execution of this code, the finally block is executed -- no matter what happens in the try block. In the example above, we exit the method (return) for various error conditions, but when the method is exited, the finally block is executed. In this way, we can execute a series of Java statements, and guarantee that no matter what happens in those statements, some other processing will follow.
Whether this programming style is "good" is a matter of opinion. Saying "return" with the idea that some cleanup will be done by a finally block could be viewed as a little sneaky or confusing, or alternatively this might turn out to be a common Java idiom in a few months or years. At the least, you might put in a comment like:
if (condition)
return; // proceed to cleanup phase of method
If an exception is thrown in a try block, and there is a local catch block to handle it, the catch block is executed, and then the finally block. If there is not a local catch block, the finally block is executed, and then the exception is propagated to the nearest catch block that can handle the exception (that is, the stack is unwound, as in other exception processing).
We will say more about Java exception handling at some future point.
COMPARING C/C++ AND JAVA PART 10 - LABELLED BREAK AND CONTINUE
In C and C++, the break and continue statements are used to break out of and continue with the next iteration of loops, for example while or for loops. break is also used in switch statements.
Such breaking and continuing apply only to the enclosing loop. Sometimes you'd like more flexibility, for example the ability to break out two levels. In C, you might say:
for (i = 1; i <= 10; i++) {
for (j = 1; j <= 10; j++) {
if (some condition)
goto done;
/* other processing in loop */
}
}
done:
/* other processing */
This effect could also be achieved by breaking out of the inner loop, and then testing some program state variable, and then breaking out of the outer loop.
In Java, there's a simpler approach to solving this problem. The above could be written as:
outer_block:
for (i = 1; i <= 10; i++) {
for (j = 1; j <= 10; j++) {
if (some condition)
break outer_block;
// other processing in loop
}
}
// control comes here when break is executed
The break statement has a label. When the statement is executed, control transfers out of the enclosed labelled statement. Control is NOT transferred to the label, but to a point past the end of the labelled statement. A labelled continue statement works in a similar way; control is transferred to the end of a labelled loop.
Note that with both break and continue, any finally block will be executed before the labelled statement is exited or the next iteration of a loop takes place. For example:
loop:
while (some condition) {
try {
if (some condition)
continue loop;
// other processing
}
finally {
// some processing
}
}
The labelled continue statement will cause the finally block to be executed before going to the bottom of the while loop in preparation for the next iteration of the loop.
PERFORMANCE - GARBAGE COLLECTION AND SETTING TO NULL
In issue #001 we talked about Java garbage collection, where the runtime system automatically reclaims dynamic storage that is no longer in use. For example:
public class test {
public void f()
{
char buf[] = new char[1024];
// stuff that uses buf
}
}
When method f() exits, the space that buf uses is garbage, because only a local variable in an invalid stack frame references it. The runtime system may eventually reclaim the storage.
Garbage collection is automatic. But sometimes there are ways to help it out. Consider a case where you are managing a stack of Object references:
public class Stack {
private static final int MAXLEN = 10;
private Object stk[] = new Object[MAXLEN];
private int stkp = -1;
// add in logic for error checking, stack growing, etc. ...
public void push(Object p)
{
stk[++stkp] = p;
}
public Object pop()
{
return stk[stkp--];
}
}
Consider a case where the stack has two elements on it, and you pop one of them. At this point stk[0] will have a valid element in it, and stk[1] will have the element just popped. That is, stk[1] will have a reference to an Object, which could be a reference to anything, including a large data structure of many thousands of bytes. In such a case, this data structure cannot be garbage collected, even though it may no longer be in use.
To remedy this problem, we can rewrite pop() like so:
public Object pop()
{
Object p = stk[stkp];
stk[stkp--] = null;
return p;
}
We haven't nullified the Object itself, just a no longer valid reference to it. The Stack object itself may have a long lifetime, and rewriting the pop() method in this way helps ensure that garbage collection can be done in a timely way.
NEWSLETTER WRITING
Would your company find it valuable to have a customized newsletter on C++ or Java or related topics, similar to this newsletter that you're reading right now? If so, please contact me (glenm@glenmccl.com) for further information. Custom newsletters can consist of technical material furnished from outside, internal material with outside editting, or a combination of the two.
INTRODUCTION TO APPLET PROGRAMMING PART 6 - TEXT FIELDS
In the previous issue we showed how to use low-level character input within an applet. In this issue we'll discuss higher-level input using TextFields. Consider the following example, an applet that gathers name and address from a user and writes the data to a local file:
import java.applet.*;
import java.awt.*;
import java.io.*;
public class text4 extends Applet {
TextField tf1; // text fields for address
TextField tf2;
TextField tf3;
Button db; // Done button
Label lb; // Label used as message
Color bg = new Color(0xffffff); // background/foreground clrs
Color fg = new Color(0x000000);
public void init()
{
// set colors
setForeground(fg);
setBackground(bg);
// create text fields
tf1 = new TextField(35);
tf2 = new TextField(35);
tf3 = new TextField(35);
// create button and label
db = new Button("Done");
lb = new Label();
// arrange items in window
setLayout(new GridLayout(4, 2, 10, 10));
add(new Label("Name:"));
add(tf1);
add(new Label("Address #1:"));
add(tf2);
add(new Label("Address #2:"));
add(tf3);
add(db);
add(lb);
}
private boolean write()
{
// check input fields
if (tf1.getText() == null ||
tf1.getText().length() == 0)
return false;
if (tf2.getText() == null ||
tf2.getText().length() == 0)
return false;
if (tf3.getText() == null ||
tf3.getText().length() == 0)
return false;
// write out name and address to end of file
try {
RandomAccessFile raf = new
RandomAccessFile("datafile", "rw");
raf.seek(raf.length());
raf.writeBytes(tf1.getText());
raf.writeByte('\n');
raf.writeBytes(tf2.getText());
raf.writeByte('\n');
raf.writeBytes(tf3.getText());
raf.writeByte('\n');
raf.writeByte('\n');
raf.close();
}
catch (Throwable e) {
}
return true;
}
public boolean action(Event e, Object o)
{
// Done button selected
if (e.target == db) {
if (write())
lb.setText("Written ...");
else
lb.setText("Invalid field value");
return true;
}
else {
return false;
}
}
}
This applet uses the following HTML code to drive it:
<html>
<body bgcolor="#ffffff" text="#000000" link="#ff0000" vlink="#000000">
<head>
<title>Interface to Text Applet</title>
</head>
<body>
Please enter your name and address then select Done.
<br>
<br>
<applet code="text4.class" width=350 height=125></applet>
</body>
</html>
In this example, we use the init() method of the applet to set the background and foreground colors, and then we create the individual items of the window. We use a layout manager for this purpose. A layout manager is a mechanism for arranging items in a window, or more precisely, Component objects in a Container. Applet is derived from Panel which is derived from Container. And an item like TextField is derived from TextComponent which is derived from Component.
So when we create text fields and buttons and so on, we are creating objects of classes derived from Component, and using a layout manager to arrange these objects in a Container object.
After we've set up the window items, we can then add some logic within the action() method to check whether the user selected the Done button, and if so, then we interrogate the text fields using getText() and extract the input data. Finally, we write this data to a file. We append to the end of the file by obtaining its length and positioning at the end of file.
ACKNOWLEDGEMENTS
Thanks to Thierry Ciot, Irv Kanode, and Mike Paluka for help with proofreading.
SUBSCRIPTION INFORMATION / BACK ISSUES
To subscribe to the newsletter, send mail to majordomo@world.std.com with this line as its message body:
subscribe java_letter
Back issues are available via FTP from:
rmi.net /pub2/glenm/javalett
or on the Web at:
There is also a C++ newsletter. To subscribe to it, say:
subscribe c_plus_plus
using the same majordomo@world.std.com address.
-------------------------
Copyright (c) 1996 Glen McCluskey. All Rights Reserved.
This newsletter may be further distributed provided that it is copied in its entirety, including the newsletter number at the top and the copyright and contact information at the bottom.
Glen McCluskey & Associates
Professional Computer Consulting
Internet: glenm@glenmccl.com
Phone: (800) 722-1613 or (970) 490-2462
Fax: (970) 490-2463
FTP: rmi.net /pub2/glenm/javalett (for back issues)
Web: http://rmi.net/~glenm