Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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)