Download Assertions, Exceptions, etc

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
COMP2059 – Sun Certified Java Programmer
Assertions
(p371-382)
Example
Consider the Student class from a previous lab. Here the constructor calculates a random score for
the student. An assert statement can be used to check that the calculated score lies in the legal
range. This is shown here with a deliberate mistake made in the calculation:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
public class Exam {
public static void main(String[] args) {
Student scjp = new Student("Fred");
System.out.println(scjp.getResult());
}
}
class Student {
protected String name;
protected int score;
public Student(String name) {
this.name = name;
score = (int)Math.round(Math.random() * 150);
assert (score >= 0 && score <= 100) : score;
}
public String getResult() {
return name + " " + score;
}
}
Assertions were introduced to Java in version 1.4. Thus only 1.4 compilers and above recognise
assert as a keyword; earlier compilers will see it as an identifier. Try compiling the above with
each of these commands and describe what happens:
Command Line
javac -source 1.2 Exam.java
javac -source 1.3 Exam.java
javac -source 1.4 Exam.java
javac -source 1.5 Exam.java
javac -source 5 Exam.java
javac Exam.java
Result
Note: the last three commands are equivalent if you are using the 1.5 version of the compiler
(which you should be).
Generally if you are writing new code you will be using an up-to-date compiler, so using new
features of the language are not a problem. However by making assert a keyword where it
previously wasn't we break any old code where assert was used as an identifier. Hence the ability
of Java compilers to emulate old version using the -source command switch.
Now try running the Exam application normally several times, you should get various outputs.
Notice that the score is sometimes greater than 100 (due to our intentional bug). If you weren't
consciously looking for this problem this might get by you. More importantly it may break other
code that is dependant on it.
Now try running the Exam application several times with assertions enabled, ie use:
java -ea Exam
Now whenever the score is more than 10 you will see a message something like:
By default assertions are disabled at run-time; to enable them you need to use the -ea (or enableassertions) switch. The -da (or -disableassertions) switch disables assertions at runtime. Assertions can be enabled and disabled globally, package-by-package, or class-by-class using
combinations of the -ea and -da switches. (A favourite exam question, but we also need to know a
bit about packages for this - save until later).
Exceptions
(p344-370)
Java provides a standard mechanism for dealing with anomalous situations: exception handling.
This is a means to deal with unusual conditions that can arise during execution and provides for
dealing with these conditions in a consistent way.
Java has a class called Throwable, from which two other major classes, Error and Exception,
inherit. Normally Throwable is not used directly but you do have to have a class that is a subclass
of Throwable to throw an error or an exception. All Throwable objects contain information on the
exception stack for the executing thread at the time the error or exception object was created.
Normally you won't write code to deal with Error or any subclass of it; an Error stems from
events like device failures or out-of-memory conditions.
Throwable
Error
Exception
RunTimeException
Other Exceptions
There are many subclasses of Exception. Of these RunTimeExceptions are not normally dealt
with in your code. Such exceptions probably represent a program bug, eg if your code tries to
access an array element that does not exist, such as the 6th element of a 5-element array object, this
would cause an ArrayIndexOutOfBoundsException. Another example that would generate a
RunTimeException is trying to use an object before it is instantiated. RunTimeExceptions
represent problems in your code, you should not try to catch them, but rather resolve the problems
in your code.
There are many Exception subclasses that do not represent RunTimExceptions, but are generated
by other conditions in a program. These are called checked exceptions and Java requires that you
deal with these. These may be thrown by the JVM. Another situation is where a developer has
decided that their code needed to throw the exception under given circumstances. Such an
exception might not represent a bug or logic problem, but rather it might merely be an anomalous
condition that you might want to try to deal with in your code. Even if you do not want to deal with
the condition, the Java compiler won't let you not do something about a thrown checked exception.
Java has a rule: its the "handle or declare rule". At compile time, the compiler verifies that all
checked exceptions are handled or declared in your code; at runtime the Java Virtual Machine
implements your choice.
Thus you either need to deal with a checked exception, or tell Java to pass the exception up the call
stack to your method's caller. Java will continue up the call stack looking for some method that will
deal with the exception. If it runs out of methods, the exception is handled by the Java runtime by
interrupting execution and displaying the exception on System.err (normally the console).
Handling Exceptions
The mechanism Java has for dealing with Exceptions is the try-catch-finally construct. The
basic syntax is:
try {
//put code that might throw
//an Exception inside a try block
} catch(<SomeExceptionClass> excpObjRef) {
//name a specific exception class and object reference
//put code here to deal with the
//Exception type if it is thrown
} finally {
//a finally block is optional
//if present it is always executed, use it to
//do something that needs to be done no matter what
}
Where a method that you call may throw checked exception, you call it inside a try block (or
clause). The best way to know if a method can throw an exception (or many exceptions) is to check
the API documentation:
If the exception is to be handled, the method or constructor call should be inside a try block. One
or more catch blocks should contain the code to handle the exception(s) and followed optionally
with a finally block. For one try block you can have essentially any number of catch blocks.
Java processes catch blocks by examining the type of Exception class listed in the catch block
parameter list. The first catch block whose Exception type matches, or is a superclass of the type
of exception thrown from the try block is executed.
Example - Using try ... catch ... finally
The Integer class wraps a value of the primitive type int in an object. An object of type Integer
contains a single field whose type is int. In addition, this class provides several methods for
converting an int to a String and a String to an int, as well as other constants and methods
useful when dealing with an int. See the Java API documentation for details. The Integer class
has a constructor as shown:
public Integer(String s) throws NumberFormatException
Thus if the String is of numeric integer format the Integer object will be created, otherwise a
NumberFormatException will be thrown. The following application uses this to determine if a
command line argument is an integer or not:
public class ExDem1 {
public static void main(String[] arg) {
try {
Integer num = new Integer(arg[0]);
System.out.println(num.intValue() + " is an integer");
} catch (NumberFormatException e) {
System.out.println(arg[0] + " is not an integer");
} finally {
System.out.println("No matter what, have a nice day!");
}
}
}
In the try block a new Integer object is created with the value of the command line argument. If
this is successful a message is output to say the value is an integer. If an exception occurs during
the creation of the Integer object the remainder of the try block is not executed; instead the
appropriate catch clause is. Here the only exception that can be thrown is the
NumberFormatException,
so there is a catch block specifically for it. If more than one exception
could have been thrown there could be multiple catch clauses to handle each, or a catch block for
a superclass of the exception classes could be used to handle them all. The finally block is always
executed no matter whether an exception occurred or not, so the "have a nice day" message will
always be output. Experiment, running this application with various command line arguments.
Exercise
Try running the above application without a command line argument. An
ArrayIndexOutOfBoundsException occurs. This is not a checked exception, so the Java compiler
does not require that we handle or declare it. Normally this exception is thrown due to a program
bug and so wouldn't normally be handled. However here it is thrown as a result of user actions and
hence should be handled.
Modify the above example to deal in a user-friendly way with the situation where the user doesn't
put in a command line argument (use exception handling to do this).
Example - Throwing an Exception
As well as catching exceptions, your code can throw them as well. Throwing an exception is done
with the throw keyword. This exception must either be handled or declared in the signature of the
method within which it can occur (unless in the main method). Consider extending the above
example to throw and catch an exception if the number entered is odd.
public class ExDem2 {
public static void main(String[] arg) {
try {
Integer num = new Integer(arg[0]);
if ((num.intValue() % 2) != 0) throw new ArithmeticException();
System.out.println("number is even");
} catch (NumberFormatException e) {
System.out.println("only integers allowed");
} catch (ArithmeticException e) {
System.out.println("number is odd");
} finally {
System.out.println("No matter what, have a nice day!");
}
}
}
Exercise
Apply your solution to the no command-line argument problem to this example too.
Example - Creating Your Own Exception Class
You can also create your own exception subclass by extending the Exception class. Exception
subclasses need to provide some common elements. There needs to be a String to store the reason
for the exception. Also, there needs to be a constructor for the exception, which accepts a String to
put into the reason data member. The getMessage() method may optionally be overridden to
return the reason for the exception together with other desired information; alternatively the
inherited version of getMessage() may be used.
The following shows an OddException class to handle an exception when a number is odd (instead
of using the more general ArithmeticException):
public class OddException extends Exception {
String message = "";
public OddException(String reason) {
message = reason;
}
public String getMessage() {
return message;
}
}
The application code that uses it is:
public class ExDem3 {
public static void main(String[] arg) {
try {
Integer num = new Integer(arg[0]);
if ((num.intValue() % 2) != 0) throw new OddException(arg[0]);
System.out.println("number is even");
} catch (NumberFormatException e) {
System.out.println("NumberFormatException: " + e.getMessage());
System.out.println("only integers allowed");
} catch (OddException e) {
System.out.println("OddException: " + e.getMessage());
System.out.println("number is odd");
} finally {
System.out.println("No matter what, have a nice day!");
}
}
}
Exercise
Experiment with this code and satisfy yourself that it performs as expected. Again apply your
solution to the no command-line argument problem to this example too.
AutoBoxing and AutoUnboxing
(p227-237)
Exercise
Check out this modified version of the ExDem2 example above. In what places in this code does
boxing or unboxing occur automatically?
01
02
03
04
05
06
07
08
09
10
11
12
13
public class ExDem2b {
public static void main(String[] arg) {
Integer num = 0;
try {
num = new Integer(arg[0]);
if ((num % 2) != 0) throw new ArithmeticException();
System.out.println(num + " is even");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Please try again with a command-line argument");
} catch (NumberFormatException e) {
System.out.println("only integers allowed");
} catch (ArithmeticException e) {
14
15
16
17
18
19
System.out.println(num + " is odd");
} finally {
System.out.println("No matter what, have a nice day!");
}
}
}
(To get the answer compile the code with the -source 1.4 switch)