Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ganesh_JavaSE7_Programming_1z0-804_study_guide.pdf
Скачиваний:
94
Добавлен:
02.02.2015
Размер:
5.88 Mб
Скачать

Chapter 11 Exceptions and Assertions

First compile and run this program before reading the discussion of the code.

D:\> java CustomExceptionTest Type an integer in the console: one

Wrapping up the exception and throwing it...

Error: Invalid input in console...

The current caught exception is of type: InvalidInputException: Invalid integer input typed in console

The originally caught exception is of type: java.util.InputMismatchException

In this code, you use InvalidInputException just like any other exception already defined in the Java library. You are catching the InvalidInputException thrown from the readIntFromConsole() method in the main() method. The following statement invokes the toString() method of the InvalidInputException:

System.out.println("The current caught exception is of type: " + iie);

You did not override the toString() method, so the InvalidInputException class inherits the default implementation of the toString() method from the RuntimeException base class. This default toString() method prints the name of the exception thrown (InvalidInputException) and it also includes the detailed information string (“Invalid integer input typed in console”) that you passed while creating the exception object. The last statement in the main() method is to get the cause of the exception.

System.out.println("The originally caught exception is of type: " + iie.getCause());

Since the cause of InvalidInputException is InputMismatchException, this exception name is printed in the console as a fully qualified name, java.util.InputMismatchException. You can think of InputMismatchException causing InvalidInputException; these two exceptions are known as chained exceptions.

Assertions

When creating application programs, you assume many things. However, often it happens that the assumptions don’t hold, resulting in an erroneous condition. The assert statement is used to check or test your assumptions about the program.

The keyword assert provides support for assertions in Java. Each assertion statement contains a Boolean expression. If the result of the Boolean expression is true, it means the assumption is true, nothing happens. However, if the Boolean result is false, then the assumption you had about the program holds no more, and an AssertionError is thrown. Remember that the Error class and its derived classes indicate serious runtime errors and are not meant to be handled. In the same way, if an AssertionError is thrown, the best course of action is not to catch the exception and to allow the program to terminate. After that, you need to examine why the assumption did not hold true and then fix the program.

There are many reasons why you should add assertions to the program. One reason is that it helps find the problems early; when you check your assumptions in the program, and when any of them fail, you immediately know where to look out for the problem and what to fix. Also, when other programmers read your code with assertions, they will be in a better position to understand the code because you are making your assumptions explicit using assertions.

Assert Statement

Assert statements in Java are of two forms:

assert booleanExpression;

assert booleanExpression : "Detailed error message string";

350

Chapter 11 Exceptions and Assertions

It is a compiler error if a non-Boolean expression is used within the assert statement. Listing 11-25 contains the first example for assertions.

Listing 11-25.  AssertionExample1.java

class AssertionExample1 {

        public static void main(String []args) {

                int i = -10;

                if(i < 0) {

                        // if negative value, convert into positive value

                        i = -i;

                }

                System.out.println("the value of i is: " + i);

                // at this point the assumption is that i cannot be negative;

                // assert this condition since its an assumption that will always hold

                assert (i >= 0) : "impossible: i is negative!";

        }

}

In this program, you are checking if the value of i is < 0; you are using the expression –i to convert it to a positive value. Once the condition check if (i < 0) is completed, the value of i cannot be negative, or that is your assumption. Such assumptions can be asserted with an assert statement. Here is the assert statement:

assert (i >= 0) : "impossible: i is negative!";

The program will run fine if the Boolean expression (i >= 0) evaluates to true. However, if it evaluates to false, the program will crash by throwing an AssertionError. Let’s check this behavior (you need to use the –ea flag to enable assertions at runtime; we will discuss more about this flag in a moment).

D:\>java -ea AssertionExample1 the value of i is: 10

Yes, this program executed successfully without throwing any exceptions.

Is there any value of i for which the condition will fail? Yes, there is! If the value of i is a minimum possible value of integer, then it cannot be converted into a positive value. Why? Remember that the range of integers is -231 to 231 – 1, so the integer values the value of i as –2147483648 to 2147483647. In other words, the positive value 2147483648 is not in the range of integers. So, if the value of i is –2147483648, then the expression -i will overflow and again result in the value –2147483648. Thus, your assumption is not true.

In Listing 11-25, change the value of i to the minimum value of an integer, as in the following:

int i = Integer.MIN_VALUE;

Now, try running this program.

D:\> java -ea AssertionExample1 the value of i is: -2147483648

Exception in thread "main" java.lang.AssertionError: impossible: i is negative! at AssertionExample1.main(AssertionExample1.java:12)

In this output, note how the assertion failed. The application crashes because the program threw the AssertionError, and there is no handler, so the program terminates.

351

Chapter 11 Exceptions and Assertions

You saw that assertions are disabled at runtime; to enable assertions at runtime, use an -ea switch (or its longer form of -enableasserts). To disable assertions at runtime, use a -da switch. If assertions are disabled by default at runtime, then what is the use of -da switch? There are many uses. For example, if you want to enable assertions for all classes within a given package and want to disable asserts in a specific class in that package, then a -da switch is useful. Table 11-5 lists the important command-line arguments and their meaning. Note that you need not recompile your programs to enable or disable assertions; just use the command-line arguments when invoking the JVM to enable or disable them.

Table 11-5.  Important Command-Line Arguments for Enabling/Disabling Assertions

 

 

Command-Line Argument

Short Description

-ea

Enables assertions by default (except system classes).

-ea:<class name>

Enables assertions for the given class name.

-ea:<package name>...

Enables assertions in all the members of the given package <package name>.

-ea:...

Enable assertions in the given unnamed package.

-esa

Short for -enablesystemsassertions; enables assertions in system classes. This

 

option is rarely used.

-da

Disable assertions by default (except system classes).

-da:<class name>

Disable assertions for the given class name.

-ea:<package name>...

Disables assertions in all the members of the given package <package name>.

-da:...

Disable assertions in the given unnamed package.

-dsa

Short for -disablesystemsassertions; disables assertions in system classes.

 

This option is rarely used.

 

 

How Not to Use Asserts

The key to understanding assertions is that they are useful for debugging and testing applications, and assertions are meant to be disabled when the application is deployed to end users.

Don’t use assertions for validating input values or for validating arguments to public methods. For signaling such runtime failures, use exceptions instead.

Don’t use assertions to check conditions that are required for the correct functioning of the application. Since assertions are disabled by default at runtime, the application will not function correctly when the asserted conditions are not present in the code.

The Boolean expressions given inside assert statements should not have side effects— modifying variable values, printing values to console, etc. In other words, the functioning of the application should remain the same no matter if assertions are enabled or disabled.

352

Chapter 11 Exceptions and Assertions

Question Time!

1.Consider the following class hierarchy from the package java.nio.file and answer the question.

Exception

IOException

FileSystemException

AccessDeniedException

DirectoryNotSupportedException

AtomicMoveNotSupportedException FileAlreadyExistsException

In the following class definitions, the base class Base has the method foo() that throws a FileSystemException; the derived class Deri extending the class Base overrides the foo() definition.

class Base {

        public void foo() throws FileSystemException {

                throw new FileSystemException("");

        }

}

class Deri extends Base {

        /* provide foo definition here */

}

Which of the following overriding definitions of the foo() method in the Deri class are compatible with the base class foo() method definition? Choose all the foo() method definitions that could compile without errors when put in the place of the comment: /* provide foo definition here */

A.

public void foo() throws IOException { super.foo();

}

B.

public void foo() throws AccessDeniedException {

           throw new AccessDeniedException("");

}

353

Chapter 11 Exceptions and Assertions

C.

public void foo() throws FileSystemException, RuntimeException {

           throw new NullPointerException();

}

D.

public void foo() throws Exception {

           throw new NullPointerException();

}

Answer: B and C.

(In option A and D, the throws clause declares to throw exceptions IOException and Exception respectively, which are more general than the FileSystemException, so they are not compatible with the base method definition. In option B, the foo() method declares to throw AccessDeniedException, which is more specific than FileSystemException, so it is compatible with the base definition of the foo() method. In option C, the throws clause declares to throw FileSystemException, which is the same as in the base definition of the foo() method. Additionally it declares to throw RuntimeException, which is not a checked exception, so the definition of the foo() method is compatible with the base definition of the foo() method).

2.Consider the following program:

class ChainedException {

        public static void foo() {

                try {

                        throw new ArrayIndexOutOfBoundsException();

                } catch(ArrayIndexOutOfBoundsException oob) {

                        RuntimeException re = new RuntimeException(oob);

                        re.initCause(oob);

                        throw re;

                }

        }

        public static void main(String []args) {

                try {

                        foo();

                } catch(Exception re) {

                        System.out.println(re.getClass());

                }

        }

}

When executed, this program prints which of the following?

A.class java.lang.RuntimeException

B.class java.lang.IllegalStateException

354

Chapter 11 Exceptions and Assertions

C.class java.lang.Exception

D.class java.lang.ArrayIndexOutOfBoundsException Answer: B. class java.lang.IllegalStateException

(In the expression new RuntimeException(oob);, the exception object oob is already chained to the RuntimeException object. The method initCause() cannot be called on an exception object that already has an exception object chained during the constructor call. Hence, the call

re.initCause(oob); results in initCause() throwing an IllegalStateException.)

3.Consider the following program:

class ExceptionTest {

        public static void foo() {

                try {

                        throw new ArrayIndexOutOfBoundsException();

                } catch(ArrayIndexOutOfBoundsException oob) {

                        throw new Exception(oob);

                }

        }

        public static void main(String []args) {

                try {

                        foo();

                } catch(Exception re) {

                        System.out.println(re.getCause());

                }

        }

}

Which one of the following options correctly describes the behavior of this program?

A.java.lang.Exception

B.java.lang.ArrayIndexOutOfBoundsException

C.class java.lang.IllegalStateException

D.This program fails with compiler error(s)

Answer: D. This program fails with compiler error(s)

(The foo() method catches ArrayIndexOutOfBoundsException and chains it to an Exception object. However, since Exception is a checked exception, it must be declared in the throws clause of foo(). Hence this program results in this compiler error:

ExceptionTest.java:6: error: unreported exception Exception; must be caught or declared to be thrown

throw new Exception(oob);

^

1 error)

355

Chapter 11 Exceptions and Assertions

4.Consider the following program:

import java.io.*; import java.sql.*;

class MultiCatch {

        public static void fooThrower() throws FileNotFoundException {

                throw new FileNotFoundException();

        }

        public static void barThrower() throws SQLException {

                throw new SQLException();

        }

        public static void main(String []args) {

                try {

                        fooThrower();

                        barThrower();

} catch(FileNotFoundException || SQLException multie) {

                        System.out.println(multie);

                }

        }

}

Which one of the following options correctly describes the behavior of this program?

A.This program prints the following: java.io.FileNotFoundException.

B.This program prints the following: java.sql.SQLException.

C.This program prints the following: java.io.FileNotFoundException || java.sql.SQLException.

D.This program fails with compiler error(s).

Answer: D. This program fails with compiler error(s).

(For multi-catch blocks, the single pipe (|) symbol needs to be used and not double pipe (||), as provided in this program. Hence this program will fail with compiler error(s).)

5.Consider the following class hierarchy from the package javax.security.auth.login and answer the questions.

LoginException

AccountException

AccountExpiredException AccountLockedException AccountNotFoundException

356

Chapter 11 Exceptions and Assertions

5.1.Which of the following handlers that makes use of multi-catch exception handler feature will compile without errors?

A.catch (AccountException | LoginException exception)

B.catch (AccountException | AccountExpiredException exception)

C.catch (AccountExpiredException | AccountNotFoundException exception)

D.catch (AccountExpiredException exception1 | AccountNotFoundException exception2)

Answer: C. catch (AccountExpiredException | AccountNotFoundException exception)

(For A and B, the base type handler is provided with the derived type handler, hence the multicatch is incorrect. For D, the exception name exception1 is redundant and will result in a syntax error. C is the correct option and this will compile fine without errors).

5.2.Consider the following code segment, which makes use of this exception hierarchy:

try {

LoginException le = new AccountNotFoundException();

     throw (Exception) le;

}

catch (AccountNotFoundException anfe) {

System.out.println("In the handler of AccountNotFoundException");

}

catch (AccountException ae) {

System.out.println("In the handler of AccountException");

}

catch (LoginException le) {

System.out.println("In the handler of LoginException");

}

catch (Exception e) {

System.out.println("In the handler of Exception");

}

When executed, which of the following statements will this code segment print?

A.In the handler of AccountNotFoundException

B.In the handler of AccountException

C.In the handler of LoginException

D.In the handler of Exception

Answer: A. In the handler of AccountNotFoundException

(In this code, the created type of the exception is AccountNotFoundException. Though the exception object is stored in the variable of type LoginException and then typecasted to Exception, the dynamic type of the exception remains the same, which is

AccountNotFoundException. When looking for a catch handler, the Java runtime looks for the exact handler based on the dynamic type of the object. Since it is available immediately as the first handler, this exactly matching catch handler got executed.)

357

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]