09
-
9.0 Exceptions
- Exceptions (named from the term 'exceptional event') are event that occur during the execution of a program that interrupt the flow of the programs normal operation, i.e. when a serious problem occurs, the program will throw an exception. Throwing an exception creates an exception object which is handed over to the runtime system. Exception objects details the type of error, location and state of the program. Runtime system attempts to handle exception by looking in the call stack and searching through the ordered list of methods invoked prior to exception the being thrown in order to get to the method where the error occurs. The is achieved by sreaching the methods for a block of code that can handle the exception, known as the exception handler. When the appropriate exception handler has been found and object is passed to the exception handling block.
-
java.io.FileNotFoundException: modulesa.txt (The system cannot find the file specified) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at java.io.FileInputStream.<init>(FileInputStream.java:93) at java.io.FileReader.<init>(FileReader.java:58) at students.dao.textdao.textModuleDAO.loadModules(TextModuleDAO.java:32) at students.Students.loadModules(Students.java:99) at students.Students.main(Students.java:31)
- The exception handler catches the exception and provides code to resolve error or provides a graceful way for the program to stop execution. If no exception handler is found then runtime system terminates the execution with a generic error message.
- 🔗 Class Exception
- 🔗 Class FileNotFoundException
- Kinds Of Exceptions
- Checked exception
- Conditions that the application should detect and be able to recover from
- e.g. attempting to open a non-existent file
- Error exception
- Circumstances external to program which program is not expected to recover from
- e.g. disk fault
- Runtime exception (unchecked)
- Internal to application but program not expected to recover from
- e.g. logic errors
- Not checked at compile time
- Throw statements
- Single Throwable object
- throw someThrowableObject;
- Error class:
- Java virtual machine throws an error
- typically programs do not catch or throw Errors
- Exception class:
- Problem has occurred which can be recovered from
- Also for actions to allow a program to die gracefully
- Runtime exceptions reserved for misuse of APIs
- The Throwable Class
-
public static int readInt(String prompt, int max, int min) { if (min > max) throw new IllegalArgumentException( String.format("min (%d) should be <= max (%", min, max) );
-
9.1 Try & Catch
- Code which may throw an exception should be placed in a "try" block and exception handling code in a "catch" block. A try block contains blocks of code in which an exception might occur, a catch block handles any exceptions that occur. Catch blocks are identified with one or more exceptions and try blocks can have more than one catch block if different exceptions have different error handling codes.
-
try { … } catch (ExceptionType name) { … } catch (ExceptionType name) { … }
- "ExceptionType" must be a class that descends from "Throwable". Handler code is executed when the runtime system detects an exception is thrown and the exception object is passed into the catch argument. A match is made if the thrown object can legally be assigned to the exception handler's argument. Exception handlers can provide a variety of code including logging exception details, prompting the user to re-enter input, undo set of actions. From Java 7 onwards a catch block can be associated with more than one exception, e.g. catch (IOException|SQLException ex).
- Finally block
- A "finally" statement must be associated with a try statement, i.e. if you want to use a finally there has to be a try statement. The finally statement will execute whether exception occurs or not unless program is terminated during exception handling. Finally statements are used to provide actions that need to take place whether an exception has occurred or not, e.g. closing a stream.
-
} finally { if (br != null) // might throw exception br.close(); }
- Try-with-resources
- Try with resources can be used when a resource is being created which must be released after an action has taken place, e.g. java.lang.AutoCloseable. They ensures the resource is released once try block has finished executing.
-
static String readFirstLineFromFile(String path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); } }
- Try catch statements allow us to separate error handling code and classifying error types into groups. They also let us propagate errors up the call stack which is the best place to handle errors in the chain of method calls.
-
9.2 Examples
- NumberFormatException
-
try { inputNumber = Integer.parseInt(input.nextLine()); if (inputNumber < min || inputNumber > max) { inputError = true; System.out.println("Number out of range"); } } catch (NumberFormatException e) { inputError = true; System.out.println("Not a valid number"); }
- FileNotFoundException - Text
-
public List<Student> loadStudents(Path path) throws FileNotFoundException { List<Student> students = new ArrayList<>(); BufferedReader br = new BufferedReader(new FileReader(path.toString())); String line = br.readLine(); while(line!=null){ String str = line.replaceAll("\"", ""); temp=str.split(Character.toString(DELIMITER)); student = new Student(studentID, …, programmeCode); students.add(student); line = br.readLine(); } br.close();
- FileNotFoundException - Cont
-
public static List<Student> loadStudents() { List<Student> students=null; Path path=Paths.get("studentsa.txt"); try { TextDAOFactory daoFactory = (TextDAOFactory) DAOFactory.getDAOFactory(1); TextStudentDAO dao = (TextStudentDAO) daoFactory.getStudentDAO(); students = dao.loadStudents(path); } catch (FileNotFoundException e) { System.out.println("Students File Not Found"); }
- FileNotFoundException - Cont
-
public List<Module> loadModules(Path path) { List<Module> modules = new ArrayList<>(); try (BufferedReader br = new BufferedReader( new FileReader(path.toString()) ) ) { … br.close(); } catch (FileNotFoundException ex) { … } catch (IOException ex) { … }
-
run: Students File No Found 1. List Students 2. List Modules 3. Quit Nov 18, 2015 1:44:46 PM students.dao.textdao.textModuleDAO loadModules SEVERE: null java.io.FileNotFoundException: modulesa.txt (The system cannot find the file specified) at java.io.FileInputStream.open0(native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at java.io.FileInputStream.<init>(FileInputStream.java:93) at java.io.FileReader.<init>(FileReader.java:58) at students.dao.textdao.TextModuleDAO.loadModules(TextModuleDAO.java:32) at students.Students.loadModules(Students.java:99) at students.Students.main(Students.java:31) Enter choice: 3 Quitting BUILD SUCCESSFUL (total time: 16 seconds)
- “Throw early, catch late” - In the Students case, the exception is bubbled up the call stack until it reaches the application allowing the user to re-enter the file name. In the Modules case, the exception is caught in the DAO load method which can do nothing but log the error. Note the stack trace of method calls
-
9.3 Assertions
- Assertions are statements that let you test something you know about your program. For example if you write a method that calculates speed of a car then you might want to assert that the speed is not greater than the top speed of the car. Assertions allow us to program defensively and they aid debugging. Document things you know (believe) to be true at a point in the code, things that if they are not true then there is something is wrong with the program. Assertions are errors not exceptions, i.e. the code will still work but can produce incorrect outcomes. As such there are no throws or try-catch statement. Assertions statement asserts a condition is true, if the condition is false the an AssertionError object is created and program terminates. Assertion checking is turned on through enabling assertions: –enableassertions or –ea. Assertions take two forms:
- Form 1:
- assert condition;
- Boolean expression
- If false AssertionError thrown
- No detail message
- Form 2:
- assert expression1:expression2
- expression1 is boolean
- expression2 produces a value (not void)
- System passes value to AssertionError constructor which uses it in creating a message detail string
- Example
-
while(line!=null){ String str = line.replaceAll("\"", ""); temp=str.split(Character.toString(DELIMITER)); try { studentID = Integer.parseInt(temp[0]); } catch (NumberFormatException e) { System.out.println(e); studentID = 0; } assert studentID>0;
-
run: java.lang.NumberFormatException: For input string: "2a" Exception in thread "main" java.lang.AssertionError at students.dao.textdao.TextStudentsDAO.loadStudents(TextStudentDAO.java:50) at students.Students.loadStudents(Students.java:64) at students.Students.main(Students.java:30) Java Result: 1 BUILD SUCCESSFUL (total time: 0 seconds)
-
run: Exception in thread "main" java.lang.AssertionError at students.dao.textdao.TextStudentsDAO.loadStudents(TextStudentDAO.java:50) at students.Students.loadStudents(Students.java:64) at students.Students.main(Students.java:30) Java Result: 1 BUILD SUCCESSFUL (total time: 0 seconds)
-
9.4 Internal Invariants
- An invariant is something that should always be true, i.e. the properties and relationships (Internal Invariants) that remain stable though the life-span of a class. Assertion can be used to check condition has been met correctly and check a value is correct at a specified point in the execution, e.g. assert studentID>0;
-
run: Exception in thread "main" java.lang.AssertionError at students.dao.textdao.TextStudentsDAO.loadStudents(TextStudentDAO.java:50) at students.Students.loadStudents(Students.java:64) at students.Students.main(Students.java:30) Java Result: 1 BUILD SUCCESSFUL (total time: 0 seconds)
- Control Flow Invariants
- Control Flow Invariants are used to mark code that should never be reached, i.e. previous options should cover all cases. e.g. default option in switch
-
public static DAOFactory getDAOFactory(int whichFactory) { switch (whichFactory) { case TEXT: return new TextDAOFactory(); // case OBJECT: // return new ObjectDAOFactory(); default: assert false : "DAO Type: " + whichFactory; return null; } }
-
run: Exception in thread "main" java.lang.AssertionError DAO Type: 2 at students.dao.DAOFactory.getDAOFactory(DAOFactory.java:39) at students.Students.loadModules(Students.java:97) at students.Students.main(Students.java:31) Java Result: 1 BUILD SUCCESSFUL (total time: 0 seconds)
- Class Invariants
- An object must satisfy a condition in order to be a valid member.
-
public boolean equals(Object o) { assert ((o instanceof Student) && (o != null)); if (o instanceof Student) { Student s = (Student)o; return s.getStudentId() == getStudentId() && s.getStudentName().equals(getStudentName()) && s.getProgrammeCode().equals(getProgrammeCode()); } else { return false; } }
- Example:
-
Student student1 = students.get(0); Student student2 = null; if (student1.equals(student2)) … Student student1 = students.get(0); Object module = modules.get(0); if (student1 == module) …
-
run: Exception in thread "main" java.lang.AssertionError at students.Student.equals(Student.java:91) at students.Students.main(Students.java:59) Java Result: 1 BUILD SUCCESSFUL (total time: 3 seconds)
- Preconditions and Postconditions
- The assert construct is not a full-blown design-by-contract (assure every component of a system lives up to its expectations) facility. However they can support an informal design-by-contract style of programming as the assert construct allows us to validate preconditions (something that must be true when a method is called) and postconditions (something that must be true after a method finishes successfully).
- Preconditions on a public method should be explicitly checked, however, do not use assertions for parameters of a public method. A private method can use assert to confirm valid parameters:
-
private void setInterval(int interval) { assert interval > 0 && interval <= 100; ... // Set the interval }
- We can test postcondition with assertions in both public and nonpublic methods:
-
public int generateRandomValue) { ... // generate random value assert num > 0 && num <=10; return num; }
- Assertions vs Exceptions Overview
- Exception
- tells user something wrong
- deal with problems
- Assertion
- documents something about program
- state true things
- documentation not just error checking
-
9.5 Logging
- One of the most common debugging aids is the ordinary print statement, System.out.println. This is used to output values of variables & messages indicating which code is being executed. Logging facilities are intended to formalize this by directing debugging information to a stream typically: System.err (can save to file). The main logging API is java.util.logging however other logging APIs are available.
- Logger Class Overview
- Logger object used to log messages
- Obtained by calling getLogger factory method
- Logger.getGlobal()
- Logger.getLogger(“logger name”)
- Methods:
- entering(String sourceClass, String sourceMethod)
- log a method entry
- exiting(String sourceClass, String sourceMethod)
- log a method return
- info(String msg)
- log an INFO message
- log(Level level, String msg, Throwable thrown)
- log a message with associated Throwable information
- Logging Levels
- Example
-
private static final logger = Logger.getLogger(Students.class.getName());
run: Nov 19, 2015 11:42:20 AM students.Students main INFO: Main Nov 19, 2015 11:42:20 AM students.Students loadStudents FINER: ENTRY Nov 19, 2015 11:42:20 AM students.Students loadStudents: number of students: FINER: RETURN 5 Nov 19, 2015 11:42:20 AM students.Students loadModules FINER ENTRY Nov 19, 2015 11:42:20 AM students.dao.textdao.TextModuleDAO loadModules java.io.FileNotFoundException: modulesa.txt (The system cannot find the file specified) 1. List Students 2. List Modules 3. Quit at java.io.FileInputStream.open)(native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at java.io.FileInputStream.<init>(FileInputStream.java:93) at java.io.FileReader.<init>(FileReader.java:58) at students.dao.textdao.TextModuleDAO.loadModules(TextModuleDAO.java:32) at students.Students.loadModules(Students.java:140) at students.Students.main(Students.java:64) Nov 19, 2015 11:42:20 AM students.Students loadModules: number of modules: FINER: RETURN 0 Enter Choice:
-
logger.info("Main");
Nov 19, 2015 11:42:20 AM students.Students main INFO: Main
-
logger.entering(Students.class.getName(), "loadStudents");
Nov 19, 2015 11:42:20 AM students.Students loadStudents FINER: Entry
-
logger.exiting(Students.class.getName(), "loadStudents", "loadStudents: number of students: ", students.size());
Nov 19, 2015 11:42:20 AM students.Students loadStudents: number of students: FINER: RETURN 5
-
Logger.getLogger(TextModuleDAO.class.getName()) .log(level.SEVERE, null, ex);
Nov 19, 2015 11:42:20 AM students.dao.textdao.TextModuleDAO loadModules SEVERE: null
-
java.io.FileNotFoundException: modulesa.txt (The system cannot find the file specified) 1. List Students 2. List Modules 3. Quit at java.io.FileInputStream.open)(native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at java.io.FileInputStream.<init>(FileInputStream.java:93) at java.io.FileReader.<init>(FileReader.java:58) at students.dao.textdao.TextModuleDAO.loadModules(TextModuleDAO.java:32) at students.Students.loadModules(Students.java:140) at students.Students.main(Students.java:64)
- Logging to a file (XML – default)
-
FileHandler handler = new FileHandler("students.log"); logger.addHandler(handler);
- Logging to a file (Formatted Text)
-
SimpleFormatter formatter = new SimpleFormatter(); handler.setFormatter(formatter);
Features Framework Supported log levels Standard appenders Popularity Cost / licence Log4J FATAL ERROR WARN INFO DEBUG TRACE AsyncAppender, JDBCAppender, JMSAppender, LF5Appender, NTEventLogAppender, NullAppender, SMTPAppender, SocketAppender, SocketHubAppender, SyslogAppender, TelnetAppender, WriterAppender Widely used in many projects and platforms Apache License, Version 2.0 Java Logging API SEVERE WARNING INFO CONFIG FINE FINER FINEST Sun's default Java Virtual Machine (JVM) has the following: ConsoleHandler, FileHandler, SocketHandler, MemoryHandler Comes with the JRE Apache Commons Logging FATAL ERROR WARN INFO DEBUG TRACE Depends on the underlying framework Widely used, in conjunction with log4j Apache License, Version 2.0 SLF4J ERROR WARN INFO DEBUG TRACE Depends on the underlying framework, which is pluggable MIT License tinylog ERROR WARNING INFO DEBUG TRACE ConsoleWriter, FileWriter, LogcatWriter, JdbcWriter, RollingFileWriter, SharedFileWriter and null (discards all log entries) Apache License, Version 2.0 Logback ERROR WARN INFO DEBUG TRACE Too many to list: see Appender JavaDoc Used in many projects like Akka, Apache Camel, Apache Cocoon, Artifactory, Gradle, Lift Framework, Play Framework, Scalatra, SonarQube, etc... LGPL, Version 2.1 -
9.6 Javadoc
- API documentation from Java source files in HTML format:
- Javadocs parses declarations and documentation comments and produces a set of HTML pages that describe (by default):
- Public and protected classes
- Nested classes
- but not anonymous inner classes
- Interfaces
- Constructors, methods, and fields
- Javadoc commands parses special tags when they are embedded within a Java documentation comments. They autogenerate a complete, well-formatted API from source code. Tags start with an at sign (@) and are case-sensitive. They must start at the beginning of a line (after any leading spaces and an optional asterisk). Tags with the same name are grouped together, types:
- Block tags:
- place block tags only in the tag section that follows the description
- @tag
- Inline tags:
- place inline tags anywhere in main description or in comments for block tags
- {@tag}
- @author name-text
- adds an Author entry with specified name text to generated documents when -author option used
- can contain multiple @author tags
- @param parameter-name description
- adds a parameter with specified parameter-name followed by specified description to Parameters section
- valid only in a documentation comment for a method, constructor, or class
- use angle brackets around parameter name to specify use of a type parameter
- @return description
- adds a Returns section with description text.
- text should describe return type and permissible range of values
- valid only in a documentation comment for a method
- @throws/@exception class-name description
- identical
- adds a Throws subheading to generated documentation, with class-name and description text
- class-name is name of exception that might be thrown by method.
- valid only in documentation comment for a method or constructor
- @version version-text
- adds a Version subheading with specified version-text value to generated documents when -version option used
- intended to hold current release number of software that this code is part of, as opposed to @since tag, which holds release number where this code was introduced
-
1.7 Javadoc example
-
/** * A constructor used when a student id has already been * allocated e.g. creating student object after loading * details from a file. * * @param studentId the student id * @param studentName the student name * @param programmeCode the programme code */ public Student(int studentId, String studentName, String programmeCode) { this.studentId = studentId; this.studentName = studentName; this.programmeCode = programmeCode; this.registeredModules = new HashSet<>(); noStudents++; } /** * A getter method for student id. * * @return the student id */ public int getStudentId() { return this.studentId; } /** * * @param path the location of the file * @return the students collection * @throws FileNotFoundException */ public abstract List<Student> loadStudents(Path path) throws FileNotFoundException;
-