Lecture 7: I/O, Threads,
Exceptions, Debugging
What You Will Learn Today
- Manage input and output using
streams and command-line arguments.
- Write to and read from object streams using
serialization.
- Create and manage multiple threads within a program.
- Throw and handle exceptions.
- Use testing and debugging
methods and tools including trace messages and
debuggers.
- A stream is an ordered sequence of bytes.
- A stream can be a string, memory, a file, another program, a network
connection, etc.
- A stream is an object used for input/output operations.
- All stream classes are defined in the java.io package.
- Streams can throw an
IOException
.
Categories of Streams
- A stream is used for reading (as a source of input) or
writing (a destination for output).
- Character streams handle 16-bit Unicode characters (e.g. text);
byte streams handle 8-bit bytes of raw binary data (e.g. images).
- Object streams are byte streams that read and write objects.
- Data streams are a store of information; processing streams
filter and manage the data in the stream.
File Streams
- Use file streams to read and write files. Reader and Writer
use text, InputStream and OutputStream use bytes.
FileReader reader = new FileReader("input.txt"); // text
characters
FileInputStream inputStream = new FileInputStream("input.dat"); // binary
bytes
FileWriter writer = new FileWriter("output.txt"); // text characters
FileOutputStream outputStream = new FileOutputStream("output.dat"); //
binary bytes
- The
read()
method returns a one- or two-byte int
which represents the character.
- You need to cast the character to
char
or byte
.
read()
returns -1 if the end of file is reached.
- When finished using a file, always close it using the
close()
method to ensure the reading/writing completes.
Streams for Text Files
- In addition, you need
BufferedReader
and PrintWriter
to read and write text files, which deal with strings.
BufferedReader in = new BufferedReader(reader);
String inputLine = in.readLine();
// returns null if end of file
is reached: no more lines to read
PrintWriter out = new PrintWriter(writer);
out.println("Hello, World!");
Standard I/O
System.in
is the standard input stream (default is
keyboard)
System.out
is the standard output stream (default is
screen)
System.err
is the standard error stream (default is
screen)
- Standard I/O can be redirected
using <, >, >>, etc.
Keyboard Class
The Keyboard class is not
part of the Java standard library, but we use it because it hides I/O details
for beginners:
- Declares and uses standard input stream
- Parses input into several tokens using StringTokenizer
- Converts input value to expected type (e.g. string, int, double);
handles conversion problems
- Handles I/O exceptions
- Many UNIX programs are started using command-line arguments such as
input and output file names and optional parameters.
java MyProgram -d file.txt
- The user's command-line arguments are stored in an array of strings.
class MyProgram { public static void main(String[] args) {
... } }
- args[0] is "-d"; args[1] is "file.txt".
- If the arguments are used incorrectly, print a Usage or Help message
explaining the proper use, and exit.
- Command-line arguments are good for automating repetitive tasks using
shell scripts.
- For your program to be portable, it should follow POSIX conventions for
command-line arguments.
- e.g. options begin with a hyphen, can appear in any order, may require
an argument etc.
- Programs that read and write to files must often format the information
for other programs to read.
- Use object streams to save and restore all instance fields of an
object automatically.
- Objects are handled in binary form, so they use streams, not writers.
MyClass myObject = ...;
ObjectOutputStream out = new ObjectOutputStream(new
FileOutputStream("myfile.dat"));
out.writeObject(myObject);
ObjectInputStream in = new ObjectInputStream(new
FileInputStream("myfile.dat"));
MyClass myObject = (MyClass) in.readObject();
- The object class must implement the Serializable interface. This is easy
to do:
public class MyClass implements Serializable
- Most Java standard library classes are serializable. A few classes (e.g.
some geometry objects) are not.
- Also, some variables should not be serialized because of security, e.g.
passwords.
- To use non-serialized instance fields:
- Declare them as
transient
. e.g. public
transient Point2D.Double myPoint;
- Override the
writeObject()
and readObject()
methods (add them to your class).
- These should call
defaultWriteObject()
and
defaultReadObject()
before writing/reading the instance fields.
- A thread is a single sequential flow of control within a program.
- Every process (running program) has at least one thread, e.g.
main
for Java applications.
- Threads can run in parallel. Threads allow multiple things to
happen at the same time.
- When the browser is running a Java applet and still letting you control
the page, it is using multithreading.
- The
Timer
class (java.util or javax.swing
)
is useful for performing repeated tasks that involve delays.
- Threads are used when programming graphical animations, e.g. the
sort demo in the
Java Tutorial.
- Use the Timer's
schedule()
method to perform a task after a
delay.
- Or use the thread's sleep() method to pause a thread.
- The
run()
method gives a thread something to do. A
thread terminates when its run method does.
To provide a run method, either:
- extend
Thread
and override run()
- implement the
Runnable
interface
- Like processes, threads are scheduled to run depending on their
priorities and other factors.
- Threads that work together must synchronize their activities to
avoid problems like race conditions, starvation and deadlock.
- Threads are covered in more detail in Operating Systems courses.
- An exception is problem in a program that needs to be addressed.
- Unlike an exception, an error is a problem from which the program
cannot recover.
- There are two things to be done about an exception: detection and
recovery.
- Exception handling is detecting an exception and passing control
to a handler method.
- A handler method separates error code from ordinary code.
- An exception immediately terminates the current method.
- It is better to quit a program that is broken than to let it keep
running and cause more damage.
- Exceptions are part of the object inheritance hierarchy.
Throwable
inherits from Object
.
-
Exception
and Error
inherit from
Throwable
. All exceptions inherit from Exception
.
- An
IOException
indicates an input/output problem e.g. file
not found, end of file.
- A
RuntimeException
can be arithmetic, illegal argument,
null pointer, index out of bounds, etc.
- If a bank account tries to withdraw more than a balance, throw an
IllegalArgumentException
.
- Other exceptions include class not found and no such method.
- Unchecked exceptions extend
RuntimeException
or
Error
. These are usually caused by bugs and preventable.
- Others are checked. These occur and are out of the programmer's
control.
Using Exceptions
- Add a
throws
specifier to a method that can throw a
checked exception.
public void read(...) throws IOException
- You can design your own exception types using a subclass.
public class OutOfRangeException extends Exception
- If an exception has no handler, an error message is printed and the
program terminates.
- If an exception is not caught and handled where it occurs, it propagates
to the calling method.
- Professional programs should catch and handle all exceptions.
- But it is better to throw a checked exception than to handle an
exception poorly.
- Don't brush your problems under the rug. Don't hide your head in the
sand.
- At minimum the catch block should print the stack trace and exit.
- To handle an exception, use a try-catch block:
try { statements } catch (ExceptionType exception) {
print-statements } finally { statements }
- You can catch more than one type of exception using multiple
catch
blocks.
- If a
finally
clause is present, always execute it, even if no
exception is thrown.
finally
is used to clean up whether there is an exception
or not, e.g. close an opened file.
- A unit test is testing a class in isolation, by itself.
- A test harness is a method that is created to test a class.
- Tests can be done by inputting data from the keyboard, from a file, or
generating test cases automatically e.g. using a loop.
- There are three sets of test cases you should use:
- Positive cases are acceptable inputs.
- Negative cases are unacceptable inputs.
- Boundary cases are at the limit of acceptable inputs.
- Sometimes you can use an oracle (slower but more reliable method of calculating the
same value) as a check.
- e.g. Math.pow(x,0.5) is slower than Math.sqrt(x) but should give about
the same answer.
- A test suite is a set of test cases that can be reused when the
program changes.
- Regression testing is rerunning old tests to make sure old bugs
do not return.
- Black box testing is testing without considering the internal
structure of the implementation.
- White box testing uses information about the program's structure.
- Test all program features, not just some of them.
- Test coverage is a measure of how many parts of a program have
been tested.
- Ideally every line of code should be used at least once in a test.
- Testing can only show the presence of bugs, not their absence.
- It is usually impossible to test all possible inputs.
- Reproduce the error. Determine one input that produces the error.
- Simplify the error. Give a simpler input to produce the error.
- Divide and conquer. Locate the exact code that produces the error.
Which class? Which method? Which line?
- Know what your program should do. What do you expect the values to
be? How many times do you expect it to loop?
- Look at all details. You can have a theory of what might be wrong,
but check the evidence.
- Understand each bug before you fix it. Otherwise your "fix" might
only be partially correct; you may need to redesign.
- A trace message or debugging statement prints messages to the
console.
System.out.println("myvariable=" + myvariable);
- A stack trace displays the stack of method calls from the main
program to the current method.
Throwable t = new Throwable();
String message = t.getMessage(System.out); // the reason why the
exception was thrown
t.printStackTrace(System.out);
- Use the Logger class instead to turn off trace messages once the program is
running correctly.
Logger logger = Logger.getLogger("global");
logger.setLevel(Level.OFF); // turns OFF messages; comment out to
turn on again
logger.info("myvariable=" + myvariable);
- Print parameters at the beginning of methods.
- Print return values at the end of methods.
- Use assertions to check whether something that should be
true really is true.
assert condition;
// equivalent to: if (!condition)
{ errorMessage(); exit(1); }
assert i >= 0;
// program ends if i is negative
- Use assertions to check method preconditions and
postconditions
- A debugger is a program that runs a program so you can analyze its
behaviour from the inside.
- A debugger is more necessary for larger programs; it is faster to use than
adding many trace messages.
- The Java SDK comes with the jdb debugger. The gdb debugger is useful for C and C++
programming.
- IDEs (Eclipse, Borland's JBuilder, Microsoft's Visual J++, Sun's Forte) come with
their own built-in
debuggers.
Debugger Essentials
- set breakpoint: set a place where the program should stop.
- single step: execute one line of the program at a time.
- stepping over methods means stopping only before and after the
method.
- stepping inside methods means stopping after each statement in
the method.
- inspect variable: view the value of a variable
Java Debugger
- To run the Java debugger, type jdb. You will see a > prompt.
- To set break points, use stop in ClassName.methodName
or stop at ClassName.lineNumber.
- To run a program within the debugger, type run ClassName.
- To view currently running threads, type threads. Look for the
thread named
main
.
- To step, type step or next.
- To display objects and variables, type print objectName.fieldName.
or dump objectName.
- Type
help to list commands. To exit the debugger, type exit.
- For more information, see the jdb documentation.
To Do After Class