Handling Errors - Java eLearning Kit For Dummies (2014)

Java eLearning Kit For Dummies (2014)

Chapter 8. Handling Errors

· Defining error sources can help you locate the errors with greater ease.

· Catching errors, instead of letting them happen, lets you control whether the application works as the user anticipates.

· Throwing (deliberately causing) an error makes it possible for you to tell the user something unexpected has happened.

lingo_fmt.tif

1. Why is it necessary to understand the various kinds of error sources?

Developers need to locate and fix errors in application code with a minimum of effort and in the shortest time, so being able to understand error sources (the cause and location of an error) makes things go faster, as explained on page 212

2. Are my applications required to catch and handle every error that the system can generate?

In some cases, it’s impossible for your application to handle an error, and it must pass the information along to the user, as explained on page 222

3. Should my application handle errors in any particular order?

Yes, you should always handle errors that provide the most specific information first and then move on to more general errors, as described on page 225

4. Is there any way to avoid certain exceptions, such as the NullPointerException ?

Java 8 makes it possible to define some kinds of data as optional by using the Optional class, as explained on page 229

5. Is my application required to handle some types of errors?

Even though an application will execute just fine without any error handling, it’s bad practice not to handle some types of errors, as shown on page 234

6. When should my application generate error information in the form of an exception?

An application normally generates an exception when it has encountered conditions that the developer couldn’t anticipate, and described on page 235

7. What sort of error information should I provide as part of an exception?

Always provide the user with the best error information that your application can generate, as explained on page 238

Except for the simplest of applications, it’s highly unlikely that you’ll ever encounter an application that is error free. Errors in coding happen for a wide variety of reasons. It isn’t enough to create an application that uses the correct code. The application must also have the right logic and use arguments in precisely the correct manner. In some cases, an error actually exists outside of the application, so the application doesn’t even have control over whether the error occurs. The best the application can do is to handle the error so that the application doesn’t crash and potentially damage the user’s data.

There are situations where the code in a particular part of your application can’t handle an error. Perhaps the code doesn’t have enough information or it doesn’t have the required rights to perform a task. In some cases, you need to interact with the user to allow the user to make the decision. These are just a few of the circumstances where your application actually has to signal an error. A Java application uses an exception to signal an error. You’ve seen exceptions in other chapters in this book. This is the first chapter where you’ll discover how to throw an exception. Throwing an exception means to create one and send it to the caller.


LINGO

A coding error represents any action that the application takes that is outside of the anticipated behavior for that application. Errors can be dramatic, such as an application crash. However, errors are often more subtle, such as displaying incorrect output or producing an unexpected result. In some cases, errors aren’t noticed by the user at all, but they do present opportunities for nefarious individuals to cause damage to the application, its data, or the system that supports it.

An exception is an alert of a sort. It describes an exceptional condition in your application and tells you that an error has occurred. Exceptions can happen for all sorts of reasons. The error might be in your code or in the application environment. For example, if your application tries to open a file that doesn’t exist, the Java Runtime Environment (JRE) will generate an exception that tells your application about the error.

Throwing an exception means to create the exception object and then send it to the part of the application that called the current code. When your application throws an exception, it creates an object that tells others that it has encountered an error it can’t fix. As the term suggests, throwing an exception is something your code does for exceptional conditions, when no other alternative is available.


Understanding Error Sources

There are many sources of error in an application. You may assume that the error is in the code, but often it isn’t. The error could exist in a library or in some other code over which the application has no control. In some cases, the error has nothing to do with the code, but with the application environment. For example, the application may not have access to a resource that it requires to work. A file might be missing, or the network connection might be down. Users also cause errors by providing incorrect input.

remember.eps For the most part, there aren’t any errors that an application can’t handle in some way when the application code is robust enough and has enough information to resolve it. However, before an application can do anything with an error, it must have the information required to resolve it. One of the best tools that a developer has to make an application robust enough to handle any errors is to classify the error and understand why it happens. That’s the purpose of the following sections — to help you understand the nature of errors so that you can do a better job of fixing them.


GO ONLINE

This single chapter can’t hope to cover every possible source of errors or the resolution of those errors. Consider this chapter a good introduction to the most common problems. In fact, it may surprise you to learn that there are entire sites devoted to the topic of exceptions and exception handling! One of the better sources of information is the Introduction to Java Exception Handling tutorial at http://tutorials.jenkov.com/java-exception-handling/index.html. You can also find interesting articles on the topic, such as those found at http://onjava.com/onjava/2003/11/19/exceptions.html and http://today.java.net/pub/a/today/2003/12/04/exceptions.html.


Classifying when errors occur

Errors can occur at various times. However, you can broadly classify when an error will occur into two categories, at compile time and runtime, as described in the following sections.

Compile time

The compiler (javac for all the examples earlier in this book) converts your application code into Java byte code. During this process, it takes the human-readable code that you write and converts it into something that the Java Runtime Environment (JRE) understands. To perform this process, the compiler must parse the code, which means it reads the code in a manner that unambiguously determines precisely what you want the application to do, when you want it to do it, and how you want the task accomplished. If you break the rules for writing unambiguous code, the compiler displays an error message. This message is actually a kind of exception.


LINGO

Parsing means to read the input you provide, such as code in human-readable form, and turn it into something else, such as Java byte code. An application can also parse user input. For example, a user could type a string that your application code turns into a number. So, parsing is the act of reading some type of input, interpreting that input in a specific way, and then producing output based on the interpreted input. A parser generates an error when the input isn’t what it expects. For example, if the user inputs a string containing the letter C, and you expected a string containing a number, such as 123, the parser will generate an exception saying that the input is incorrect.


Compile time errors are the easiest to handlebecause the compiler normally tells you precisely what’s wrong and where the error has occurred. Even if the information isn’t exact, the compiler will at least get you to the right area of the broken code so that you can look for the error it contains. The point is that you don’t have to wait for the user to find this sort of error. To produce the compiled application, you must fix the error.

Runtime

The compiler can’t find every error in your code. If the form of the code is correct (that is, you haven’t made any mistakes in typing the elements that create the application), the compiler won’t find the error. For example, if you initialize a numeric value to 5 instead of 4, the compiler can’t find the error for you because the compiler has no idea that you really meant to type 4. These sorts of mistakes create runtime errors — those errors that happen at some point during the application execution.

Runtime errors can occur at all sorts of times. Some errors are more likely to occur at specific times. The following list provides you with some ideas about when runtime errors are likely to occur:

· Initialization: When the application first starts — before it presents any sort of interface to the user or performs any useful work — it goes through an initialization phase. This is when setting a variable to the incorrect type or trying to use a variable before you initialize it will get noticed. Many resource-related errors also occur during initialization because most applications open required resources during this time.

· Operating mode: After an application initializes, it’s in operating mode. If it has a user interface, it begins interacting with the user. This is the time when user input matters most. You’ll also find incorrectly initialized variables at this time because the user (or the recipient of the application output, such as the system) will see that the output is incorrect. User requests for resources, such as a data file, also create errors during this time.

· Background processing: Most background processing errors result from the environment (such as the loss of a network connection), missing resources (such as a lost file), incorrectly initialized variables, or errors in how you told the application to perform a task. Some tasks are more commonly performed in the background than others are. For example, printing a document and downloading resources from the Internet are commonly performed in the background while the user continues to work with the application in the foreground.

· Shutdown: When the user (including the system accounts) tells the application it’s no longer needed, the application goes through a shutdown phase. During this shutdown phase, the application closes files and performs other housekeeping chores that ensure the application doesn’t leave a mess for the operating system. The most common errors that can occur during this phase are not releasing resources that your application has used and not saving data to disk. Of course, coding errors can occur at any time, and this phase of operation is no exception. You could tell the application to close five files when only four of them are actually open.


EXTRA INFO

To ensure that everyone understands precisely how the Java language is supposed to work, developers create a specification for it. This specification includes the language elements in a special language called Backus-Naur Form (BNF). Using BNF is an extremely precise method of describing a language so that there isn’t any risk of misinterpretation by anyone. You can see a sample of the BNF for the Java language at www.daimi.au.dk/dRegAut/JavaBNF.html. There are also other versions of this specification athttp://java.sun.com/docs/books/jls/second_edition/html/syntax.doc.html and http://bnf-for-java. sourceforge.net. Don’t worry too much about being able to read this specification. Most developers never learn to interpret the BNF for the languages they use — that’s the domain of compiler developers.


remember.eps The JRE will present most runtime errors it detects to you as exceptions. However, the JRE won’t catch every error in your application. You must also look at the output of your application to determine whether the output matches the expectations you have for a given input. Additionally, it’s important to look at the state of any resources you use to ensure that they’re not damaged in some way. For example, you need to ensure that any data you should save in a file actually ends up in the file when your application shuts down.

Distinguishing error types


EXTRA INFO

Java 8 has a stronger emphasis on security, which means that you’ll see more Security
Exception instances as you work with your application. Seeing an increase in security exceptions doesn’t mean your code is faulty or that Java 8 is filled with bugs — it means that Java 8 automatically locates and tells you about issues that could cause security problems as people use your application. The SecurityException documentation appears athttp://download.java.net/jdk8/docs/api/java/lang/SecurityException.html. Of course, you’ll want to know what all the hubbub is about. You can find a summary of these changes in the series of slides provided in the CON7932_Mullan.pdf file found at https://blogs.oracle.com/mullan/entry/slides_for_my_javaone_session. These changes are further explained as part of the JDK Enhancement Proposal (JEP) entries found athttp://openjdk.java.net/projects/jdk8/features. (Just match the numbers found in the slides to those on the update site.) The point is that Java 8 helps you create applications that are more secure and reliable.


Knowing when an error can occur is important. You need to understand when to look for a particular problem in your application. However, it’s also important to understand how errors occur. The kind of error determines the strategy you use to find it and what you can do to fix it. Although some errors will require that you fix the code and update the application, some errors are fixed by retrying the operation or interacting with the user in some way. The following sections discuss the types of errors that you’ll encounter most often.

Syntactical

A syntactical error is one in which the language you use to create your code is incorrect. For example, if you try to create an if statement that doesn’t include the condition in parentheses, even when the condition is present on the same line as the if statement, that’s a syntax error. The compiler will catch most of these errors for you. If the syntax of your code is incorrect, then in most cases the compiler can’t use the code to create byte code for the JRE. Here’s a list of the most common syntax errors:

· Using incorrect capitalization: One of the most common syntax errors that new developers make is to capitalize keywords, rather than use lowercase. Java is case sensitive, so using the proper case when you type your code is essential. This same error can occur with class names, variables, or any other code you type as part of your Java application. A variable named MyVar is always different from one named myVar.

· Splitting a string over two lines: In most cases, Java doesn’t care if your code appears on one or more lines. However, if you split a string across lines so that the string contains a newline character, then the compiler will object. The answer is to end the string on the first line with a double quote, add a plus sign to tell the compiler you want to concatenate (add) this string with another string and then continue the string on the next line like this:

System.out.print("This is a really long " +
"string that appears on two lines.");

· Missing parentheses: If you make a method call and don’t include the parentheses after the method name (even if you aren’t sending any arguments to the method), the compiler registers an error. For example, this code is incorrect because print() requires parentheses after it:

System.out.print;

· Forgetting to import a class: Whenever you want to use a particular Java API feature, you must import the associated class into your application. For example, if your application contains String userName;, then you must add import java.lang.String; to import the String class.

· Treating a static method as an instance method: Static methods are those that are associated with a specific class, while instance methods are associated with an object created from the class. For example, when you created the example in the section on nesting if statements in Chapter 6, you used the Character.toUpperCase() static method. If you’d tried to access the toUpperCase() method from a variable instead, the application would generate an error.

· Missing curly braces: Anytime you want a Java feature to apply to multiple lines of code, you must enclose the entire block within curly braces ({}). In most cases, the compiler will catch this error for you. For example, if you try to end a class without including the closing curly brace, the compiler will generate an error. This is one error where the compiler may not show you the precise location of the error because it can’t detect where the curly brace is missing — it simply knows that one is missing. This sort of error can also create runtime errors. For example, when an if statement is supposed to apply to multiple lines of code, but you leave out the curly braces, the if statement affects only the next line of code, and the application works incorrectly.

· Forgetting the class or object name as part of a method call: You always include the class or object associated with a method before making the method call. For example, Character.toUpperCase() and System.out.print() are correct, but simply calling toUpperCase() or print()is incorrect.

· Omitting the break clause from switch statements: It’s easy to forget to add the break clauses to a switch statement. In addition, the compiler won’t catch this error. As a consequence of leaving out the break clause, your application will continue to execute the code in a switchstatement until it encounters a break clause or the switch statement is complete. For example, the following comes from the section on executing a default task in Chapter 6, but the break clauses are commented out.

// Import the required API classes.
import java.util.Scanner;
import java.lang.Character;

public class UseAMenu03
{
public static void main(String[] args)
{
// Create the scanner.
Scanner GetChoice = new Scanner(System.in);

// Obtain input from the user.
System.out.println("Options\n");
System.out.println("A. Yellow");
System.out.println("B. Orange");
System.out.println("C. Green\n");
System.out.print("Choose your favorite color: ");
char Choice = GetChoice.findInLine(".").charAt(0);

// Convert the input to uppercase.
Choice = Character.toUpperCase(Choice);

// Choose the right color based on a switch

// statement.
switch (Choice)
{
case 'A':
System.out.println("Your favorite color is Yellow!");
//break;
case 'B':
System.out.println("Your favorite color is Orange!");
//break;
case 'C':
System.out.println("Your favorite color is Green!");
//break;
default:
System.out.println(
"Type A, B, or C to select a color.");
//break;
}
}
}

When you execute this code and answer A, the application outputs all the possible responses, as shown in Figure 8-1. If you compare this output to the output shown in Figure 6-5, you’ll see that the application isn’t working correctly.

9781118098783-fg0801.tif

Figure 8-1:

· Omitting a return statement: When you create a method that’s supposed to return a value and then don’t provide a return statement to return the value, the compiler will complain.

· Mistyping the header for the main() method: The compiler won’t complain about this problem, but you’ll see it immediately when you try to start the application. Java will complain that it can’t find the main() method. Remember that a main() method must appear like this:

public static void main (String []args)

You can create many other syntax errors. As you’ve discovered by reading this list, the compiler will find some of them, the JRE will find others, but some, like omitting the break clause of a switch statement, are left for you to figure out. You’ll discover more of these syntactical errors as the book progresses. Of the three main types of error, syntactical errors tend to be the easiest to find.

Semantic

Many people find the difference between semantic errors and syntactical (syntax) errors hard to understand, but they are different. You can see a semantic error when the syntax of your code is correct but the code usage isn’t correct. The most common semantic error is one in which the code uses a variable that isn’t initialized properly. Fortunately, the compiler finds this particular semantic error in most cases. Here’s a list of other common semantic errors you need to know about.

· Using an operator that doesn’t apply: In some situations, you might try to use an operator that doesn’t apply to the variable or variables in question. For example, you can’t use the increment operator (++) with a boolean variable. Newer versions of Java have become adept at finding this error, but you can still encounter difficulty figuring out precisely why an error occurs when you use the wrong operator in some cases. For example, MyObj1 == MyObj2 won’t compare the two objects — the equality operator works only with primitive types.

· Using incompatible types: This type of semantic error can be tricky because the compiler will flag some errors and not others. For example, if you try to assign a float to an int variable, the compiler displays an error message. On the other hand, if you assign an int to a floatvariable, the compiler performs an automatic type conversion to the int to make it a float. The problem with this second scenario is that it can silently introduce errors in your code, especially if you really did mean to use a float.

· Losing precision during a conversion: Sometimes you can apply casting incorrectly. For example, casting a float to an int works fine, but at the loss of the decimal portion of the number. This loss of precision can affect the output of your application in unexpected ways and cause the output to reflect a value other than the one you expected. The compiler never finds this sort of error because you have specifically applied a cast to the variable and the compiler expects that you know what you’re doing.

· Performing an impossible cast: It’s possible to convert between many different types in Java. However, no matter how much you’d like to convert a boolean value into an int, Java won’t let you do it. The concept of performing the cast is syntactically correct, but you’re applying it incorrectly, making this a semantic error that the compiler always catches.

· Applying scoping incorrectly: Any variable you declare inside a method has the same scope — visibility to other parts of the application, in other words — as the method. Consequently, you can’t declare a private static int variable inside a method. Instead, you must define the variable globally like this:

public class PrivateVar
{
// This declaration works.
private static int PrivateInt = 3;

public static void main(String[] args)
{
// This declaration doesn’t work.
private static int PrivateInt = 3;
}
}

You’ll encounter other types of semantic errors as the book progresses. For now, these are the most common problems you should look for in your code. Semantic errors tend to be harder to find than syntactical errors, but not nearly as hard as logical errors.

Logical

Logical errors can be extremely difficult to find because they don’t reflect any sort of coding problem or an error in the use of Java language elements. The code runs perfectly as written — it just isn’t performing the task that you expected it to perform. As a result, logical errors can be the hardest errors to find. You need to spend time going through your code looking for a precise reason for the error. Here’s a list of common logical errors that Java developers encounter:

· Using incorrect operator precedence: The order in which Java interprets operators is important. Applications often produce the wrong result because the developer didn’t include parentheses in the correct places. For example, the following example produces outputs of 11, 13, 9, and 8 from the four variables, all due to the location (or lack) of the parentheses.

public class OperatorError
{
public static void main(String[] args)
{
// Create some variables.
int MyVar1 = 5 + 4 * 3 / 2;
int MyVar2 = (5 + 4) * 3 / 2;
int MyVar3 = (5 + 4) * (3 / 2);
int MyVar4 = (5 + (4 * 3)) / 2;

// Output the result.
System.out.println(
"MyVar1: " + MyVar1 +
"\nMyVar2: " + MyVar2 +
"\nMyVar3: " + MyVar3 +
"\nMyVar4: " + MyVar4);
}
}

· Defining the wrong count: Possibly the most common logical error is counting things incorrectly. People are used to starting counts with 1, and computers often start counts with 0. So, it’s not uncommon to find that applications are precisely one off in performing a task, whether that task is running a loop or working with a collection of items.

· Assuming a condition is true when it isn’t: Developers will often look at the statement used to define a condition and assume that the statement is true (or false) without verifying the logic of the statement. The use of an or statement when you really meant to use an and statement can also cause problems. The logic employed to make decisions causes many developers, even experienced developers, a lot of problems. Always verify your assumptions for conditional statements.

· Relying on floating point numbers for precision work: You can’t assume that floating point numbers will deliver a specific number. This means you can’t check a floating point number for equality to any specific value — you must instead use a range of values to perform the check. Floating point numbers are always an approximation in Java.

· Relying on integer values to measure values: Integers are great for counting items because they’re precise. However, many integer math operations create imprecise results. This is especially true for division, because the remainder is always left off. (The number is rounded down.) Use floating point values or the BigDecimal object type when you need to measure something and precision is important.

· Misplacing a semicolon: It’s possible to create Java code that compiles and runs perfectly well despite having a semicolon in the wrong place. Here’s an example:

public class ForLoopError
{
public static void main(String[] args)
{
// Declare the variable.
int Count;

// Create the loop.
for (Count=1; Count<=10; Count++) ;
{
// Output the result.
System.out.println("Count is " + Count);
}
}
}

Notice that the semicolon appears immediately after the for statement, rather than after the code block as it should. Instead of printing individual values of Count, this example prints a single sentence that says Count is 11.

There are more ways to create logical errors than anyone can imagine. You’ll see a number of additional examples as the book progresses.

Catching Errors

All the examples from this point on in the book will include error trapping in them. The examples won’t bury you in error trapping, but they’ll make good error trapping techniques part of the application code whenever possible (and the error trapping code doesn’t completely hide the purpose of the example). With this in mind, the following sections provide an overview of the techniques used to catch errors. You’ll see three different levels of error trapping commonly employed in Java applications.


LINGO

Error trapping is the act of detecting an exception and telling the JRE that you plan to do something with it. The JRE responds by not passing the error up to the caller of the current method and instead relies on the current method to fix the problem. Error trapping is normally associated with the try portion of a try…catch statement, while error handling is normally associated with the catch portion of a try…catch statement.


Optional error handling

The phrase “optional error handling” is a bit of a misnomer. It’s optional only because Java doesn’t require you to perform it as part of using the various objects in your application. Every application you build should include some level of error handling, even if Java doesn’t require you to add it. In fact, adding error handling to every application you create, even simple test applications, will help you become proficient in this aspect of Java programming and put you ahead of developers who don’t follow this practice.

The example that follows builds on the ShowByte example found in the byte section of Chapter 2. That example causes quite a few problems because it doesn’t include any error handling. A user can type values that don’t work with the byte data type, resulting in an exception. This example corrects the flaws in that earlier example by providing error handling for those situations where the user types something unexpected.

Files needed: ShowByte.java

1. Open the editor or IDE that you’ve chosen to use for this book.

2. Type the following code into the editor screen.

// Import the required API classes.
import java.util.Scanner;
import java.util.InputMismatchException;

public class ShowByte
{
public static void main(String[] args)
{
// Create the scanner.
Scanner GetByte = new Scanner(System.in);

// Ask the user for an input.
System.out.print("Type any number: ");

// Make sure that the value is acceptable.
try
{
// Obtain a byte value.
byte MyByte = GetByte.nextByte();

// Display the value onscreen.
System.out.println("The value of MyByte is: " + MyByte);
}
catch (InputMismatchException e)
{
System.out.println("You must provide numeric input"
" between -128 and 127!\n" + e.getMessage());
return;
}
}
}

The basics of this example are precisely the same as the original ShowByte example. The application obtains input from the user and displays it onscreen.


LINGO

Error handling is the act of resolving an exception that the application has trapped. In some cases, handling the error means displaying a message to the user and asking for a correction. However, error handling can take many forms, some of them completely automated and invisible to the user. This act is normally associated with the catch portion of a try … catch statement.


The difference in this example is the try … catch statement. The try clause of the try … catch statement traps the error, which means that it detects that an exception has occurred. The catch clause of the try … catch statement takes over at this point and displays a helpful message to the user.

In the code example above, the catch clause handles a specific kind of error, the InputMismatchException object, e. Look again at Figure 2-4. The kind of error that you see for both of the incorrect inputs is an InputMismatchException. When you try an application and see information of this kind, you can use it to tailor the error handling that your application provides.

The e object also provides a number of interesting properties and methods. In this case, the example uses the getMessage() method to obtain any additional information that the exception can provide.

3. Save the code to disk using the filename ShowByte.java.

4. In your command prompt, type javac ShowByte.java and press Enter.

The compiler compiles your application and creates a .class file from it.

5. Type java ShowByte and press Enter.

The application asks you to type any number.

6. Type 3 and press Enter.

The application outputs the expected value of 3.

7. Type java ShowByte and press Enter. Then type –15 and press Enter.

The application outputs the expected value of –15.

8. Type java ShowByte and press Enter. Then type 128 and press Enter.

The value you just typed is one larger than byte can support. However, instead of outputting the exception shown in Figure 2-3, the application now outputs the helpful message shown in Figure 8-2. Notice that this message tells the user what to do to correct the problem and also includes additional information provided by the exception itself.

9781118098783-fg0802.tif

Figure 8-2:

9. Type java ShowByte and press Enter. Then type C and press Enter.

The application would normally output another exception, but in this case, it outputs a variant of the same helpful message, as shown in Figure 8-3. Using a helpful message of this sort makes it easier for the user to interact with the application, which also makes it more likely that the user will continue using it.

9781118098783-fg0803.tif

Figure 8-3:

practice_fmt.eps Notice that the output in Figure 8-3 shows null instead of additional information. Modify the catch clause of this example so that it outputs only the additional information when the getMessage() method has text to return to the user.

Handling more-specific to less-specific errors

Most applications can generate more than one exception. In addition, you may not be able to detect precisely which exceptions an application will generate. In this case, you need to provide multiple catch clauses for the try … catch statement. Each catch clause specializes in a particular kind of error. In addition, you can use generic exception handlers for those situations when your application encounters errors that aren’t within the set that you originally anticipated.

In the following exercise, you create an application that can generate multiple kinds of errors. You then add error handling code to interact with each potential exception.

Files needed: MultipleException.java

1. Open the editor or IDE that you’ve chosen to use for this book.

2. Type the following code into the editor screen.

// Import the required API classes.
import java.util.Scanner;
import java.util.InputMismatchException;
import java.lang.ArithmeticException;
import java.lang.Exception;

public class MultipleException
{
public static void main(String[] args)
{
// Create the scanner.
Scanner GetInput = new Scanner(System.in);

// Attempt to perform the task.
try
{
// Ask the user for an input.
System.out.print("Type the first number: ");
int Value1 = GetInput.nextInt();

// Ask the user for another input.
System.out.print("Type the second number: ");
int Value2 = GetInput.nextInt();

// Create the output.
int Result = Value1 / Value2;
System.out.println("Value1 / Value2 = " + Result);
}
catch (InputMismatchException e)
{
// Determine whether there is error information
// to display and output it.
if (e.getMessage() != null)
System.out.println("You must provide numeric input" +
" between -2,147,483,648 and 2,147,483,647!\n"
+ e.getMessage());
else
System.out.println("You must provide numeric input" +
" between -2,147,483,648 and 2,147,483,647!");
return;
}
catch (ArithmeticException e)
{
// Determine whether there is error information
             // to display and output it.
if (e.getMessage() != null)
System.out.println("You can't divide a value" +
" by zero!\n" + e.getMessage());
else
System.out.println("You can't divide a value" +
" by zero!");
return;
}
catch (Exception e)
{
// Determine whether there is error information
// to display and output it.
if (e.getMessage() != null)
System.out.println("The application is unable" +
" to determine precisely what went wrong.\n"
+ e.getMessage());
else
System.out.println("The application is unable" +
" to determine precisely what went wrong.\n");
return;
}
}
}

This example performs a simple task. It asks the user to provide two input values and then divides the first input value by the second. It doesn’t seem as if too much could go wrong, but this code could generate at least two exceptions and potentially others.

As with the ShowByte example in the “Optional error handling” section of this chapter, the user could input a number that is either too large for the int type to handle or is simply an incorrect value, such as the letter C. Because the act of obtaining user input comes first, the example handles the InputMismatchException first. Notice that this version of the example also deals with the situation where e.getMessage() doesn’t provide any information.

The user could also try to divide a number by 0, which generates the ArithmeticException. Because this exception can’t occur when the user is inputting the numbers, it appears second in the list of catch clauses. Notice how the code simply piles one catch clause on top of another.

The two previous exceptions are specific. They occur for a specific reason and at a specific time. The application could potentially generate some other exception. There are many ways to handle this situation and the example shows just one of them. In this case, the application handles the general Exception. This overall class encompasses every other exception that the application could possibly generate. You must always include the generic Exception last or no other exception handling code will be called.

3. Save the code to disk using the filename MultipleException.java.

4. In your command prompt, type javac MultipleException.java and press Enter.

The compiler compiles your application and creates a .class file from it.

5. Type java MultipleException and press Enter.

The application asks you to type any number.

6. Type the letter C and press Enter.

You see the expected error output shown in Figure 8-4.

9781118098783-fg0804.tif

Figure 8-4:

7. Type java MultipleException and press Enter.

The application asks you to type any number.

8. Type 23 and press Enter.

The application asks you to type another number.

9. Type 0 and press Enter.

You see another exception message, but this time it tells you not to type 0 as the second number, as shown in Figure 8-5.

9781118098783-fg0805.tif

Figure 8-5:

10. Repeat Steps 7 through 9, but this time type 5 for the second number.

You see the expected output shown in Figure 8-6.

9781118098783-fg0806.tif

Figure 8-6:

Using Optional objects to avoid exceptions

Of all the exceptions you might see when working with Java, the NullPointer
Exception (or NPE) is the most prevalent and sometimes the hardest to diagnose. A NullPointerException happens any time you pass a null value to a Java function that was expecting an actual value. The problem is that not every situation that creates an NPE is actually a problem.

Sometimes you expect to have a null value occur and need some method for dealing with it. For example, consider the situation where you want to find a specific value in a list of potential values. It’s entirely possible that you won’t find the value you want, resulting in a null value return. If you then try to process the null value, you get an NPE. Because you had expected null values to occur, finding the error can be horribly difficult.

Until now, it was hard for human developers to understand the black-and-white thinking of a computer. Java 8 now provides Optional objects to deal with the situation where a return value from a function is optional rather than required. The following exercise demonstrates how to use the Optional object to reduce the potential for unexpected NPEs.

Files needed: OptionalObject.java

1. Open the editor or IDE that you’ve chosen to use for this book.

2. Type the following code into the editor screen:

// Import the required API classes.
import java.lang.String;

public class OptionalObject
{
public static void main(String[] args)
{
// Create a test string and location.
String MyString = "Hello World!";
char Letter = 'a';

// Obtain the character.
String Chars = GetChar(MyString, Letter);

// Print the result.
System.out.println(
"Found the letter: " + Letter +
" " + Chars.length() + " times.");

// Change the location.
Letter = 'o';

// Obtain the character.
Chars = GetChar(MyString, Letter);

// Print the result.
System.out.println(
"Found the letter: " + Letter +
" " + Chars.length() + " times.");
}

public static String GetChar
(String MyString, char SearchLetter)
{
// Create an output string.
String OutString = "";

// Check each character in the string.
for (char ThisLetter : MyString.toCharArray())
if (ThisLetter == SearchLetter)

// Add the character to the string.
OutString += new 
Character(ThisLetter).toString();


// Return the result.
if (OutString.length() > 0)
return OutString;
else
return null;
}
}

You wouldn’t ever create code like this, but it provides a simple way to demonstrate how an NPE could occur. The code begins by creating a test string to use for locating specific letters. It also defines which letter to find — a in the first case, o in the second.

The call to GetChar() locates each instance of a character in the test string (or returns null when the character isn’t found). When the character is found in the test string, GetChar() returns a string with each of these characters. Printing Chars.length() tells you how many times the character appeared.

Notice the technique that the example uses to convert a char to a String. In this case, the char is boxed into a Character object, and then the toString() method is used to create the required String output. The “Automatic boxing and unboxing” section of Chapter 3 gives you more details — this is an example of how you can use manual boxing to your advantage.

3. Save the code to disk using the filename OptionalObject.java.

4. In your command prompt, type javac OptionalObject.java and press Enter.

The compiler compiles your application and creates a .class file from it.

5. Type java OptionalObject and press Enter.

You see the expected error output shown in Figure 8-7 because there is no letter “a” in the string “Hello World”.

9781118098783-fg0807.tif

Figure 8-7:

6. Change the code on the editor screen so it looks like this:

// Import the required API classes.
import java.lang.String;
import java.util.Optional;

public class OptionalObject
{
public static void main(String[] args)
{
// Create a test string and location.
String MyString = "Hello World!";
char Letter = 'a';

// Obtain the character.
Optional<String> Chars = GetChar(MyString, Letter);

// Print the result.
if (Chars.isPresent())
System.out.println(
"Found the letter: " + Letter +
" " + Chars.get().length() + " times.");
else
System.out.println(Letter + " Not Found!");

// Change the location.
Letter = 'o';

// Obtain the character.
Chars = GetChar(MyString, Letter);

// Print the result.
if (Chars.isPresent())
System.out.println(
"Found the letter: " + Letter +
" " + Chars.get().length() + " times.");
else
System.out.println(Letter + " Not Found!");
}

public static Optional<String> GetChar
(String MyString, char SearchLetter)
{
// Create an output string.
String OutString = "";

// Check each character in the string.
for (char ThisLetter : MyString.toCharArray())
if (ThisLetter == SearchLetter)

// Add the character to the string.
OutString += new 
Character(ThisLetter).toString();


// Return the result.
if (OutString.length() > 0)
return Optional.of(OutString);
else
return Optional.empty();
}
}

To use the Optional object, you must import the required class into your application. The essential flow of the application is the same as before. However, now Chars is defined as an Optional<String>. This means that if the search letter isn’t present in the search string, you can test for it using Chars.isPresent(). The result is that you don’t need to worry about the NEP because it won’t happen when the output String is null.

Notice the change in the GetChar() method as well. It has to return an Optional<String> now. In addition, you use the Optional.of() method to place the OutString value in the return value. When there are no letters to return, you use Optional.empty() instead.

7. Save the code to disk by using the filename OptionalObject.java.

8. In your command prompt, type javac OptionalObject.java and press Enter.

The compiler compiles your application and creates a .class file from it.

9. Type java OptionalObject and press Enter.

You see the expected error output shown in Figure 8-8 because the letter “a” doesn’t appear in “Hello World”, but the letter “o” does appear twice.

9781118098783-fg0808.tif

Figure 8-8:

Throwing Errors

It’s essential that your code makes every effort to fix a problem. However, there are times when your code simply doesn’t have enough information, resources, rights, or some other requirement to fix a problem. When this happens, your code throws an error by using an exception object. The term exception is appropriate because it should be the exception to the rule, rather than the first act that the application performs. Even so, applications encounter errors that require exceptional measures, and the following sections describe how to deal with these sorts of situations.

Throwing errors during exceptional conditions

In the following exercise, you create an application that can generate multiple kinds of errors. Normally, you wouldn’t throw an error if a value is in the wrong range — you’d display a message directly to the user instead. However, this example demonstrates how to throw and catch an error from within a method. As you might expect, this application includes error handling to catch a number of errors.

Files needed: ThrowException.java

1. Open the editor or IDE that you’ve chosen to use for this book.

2. Type the following code into the editor screen.

// Import the required API classes.
import java.util.Scanner;
import java.util.InputMismatchException;
import java.lang.IllegalArgumentException;

public class ThrowException
{
public static void main(String[] args)
{
// Create the scanner.
Scanner GetInput = new Scanner(System.in);

try
{
// Ask the user for an input.
System.out.print("Type a number between 1 and 10: ");
int TheNumber = GetInput.nextInt();

// Determine if the input is in the correct range.
if ((TheNumber >= 1) && (TheNumber <= 10))
// If so, display it.
System.out.println("TheNumber = " + TheNumber);
else
// If not, throw an error.
throw new IllegalArgumentException(
"The value of TheNumber is: " + TheNumber);
}
catch (InputMismatchException | IllegalArgumentException e)
{
// Determine whether there is error information
// to display and output it.
if (e.getMessage() != null)
System.out.println("Please provide a value" +
" between 1 and 10!\n" + e.getMessage());
else
System.out.println("Please provide a value" +
" between 1 and 10!");
return;
}
}
}

This example asks the user for an input between 1 and 10, and it then displays the number onscreen. Of course, the user could type something other than a number, which means that you must catch the InputMismatchException. The example provides the same sort of catch clause that you’ve seen in other examples in this chapter to handle this particular error.

In addition, the input number might not be between 1 and 10. Java can’t detect this second error. The application detects the range of numbers by using an if statement. When the number is out of the specified range, the application throws an IllegalArgumentException, which is a specific kind of exception. The application could have used a simple Exception, but it’s always better to throw a specific exception whenever possible to make the error easier to catch.

Notice that this example does something new: It uses a single catch clause to catch multiple exceptions. All you need to do to use this technique in your own applications is to separate the exceptions by using the or (|) operator.

3. Save the code to disk using the filename ThrowException.java.

4. In your command prompt, type javac ThrowException.java and press Enter.

The compiler compiles your application and creates a .class file from it.

5. Type java ThrowException and press Enter.

The application asks you to type a number between 1 and 10.

6. Type the letter C and press Enter.

You see the expected error output shown in Figure 8-9.

9781118098783-fg0809.tif

Figure 8-9:

7. Perform Steps 5 and 6 using the number 22 as the input.

You see the same error, but this time with additional information, as shown in Figure 8-10.

9781118098783-fg0810.tif

Figure 8-10:

8. Perform Steps 5 and 6 using the number 5 as the input.

This time the application displays the anticipated output, as shown in Figure 8-11.

9781118098783-fg0811.tif

Figure 8-11:

Passing errors to the caller

The examples in this book are just starting to get to the point where you’re calling methods from main(). The main() method is always the top level of your application. As you call methods, the methods that you call form additional levels. For example, a method called from main() would be at the second level of your application. (See the example in the earlier “Using Optional objects to avoid exceptions” exercise of this chapter.) If that method had to call another method, that method would be at the third level, and so on. Most applications are made up of many levels of calls. In fact, when you see an exception onscreen, it actually displays a list of the methods that called the current method in a format called the call stack.


LINGO

The call stack is a listing of methods and the order in which they are called by other methods. Knowing the call stack can help you locate the source of a potential error when it doesn’t happen at the current level of the application.


Handling errors is an essential part of good programming practice. If you want robust applications that don’t constantly crash, you need to provide good error handling. However, trying to handle an error when you don’t have enough information to handle that error is also a problem. When your code attempts to fix an error at too low a level, it hides the error from a level that could possibly fix it. Yes, you want to fix an error at the lowest possible level, but not at the expense of providing a repair that could actually end up hiding something more serious.

When you find that a particular level of an application doesn’t have the required resources, information, privileges, user access, or some other item needed to handle an error, then you issue a throw statement with the appropriate exception object. The previous level of the application will receive the exception and determine whether it can handle it. However, if the main() method receives the exception, then you must determine what to do with the error, or the application will crash. It’s generally considered bad programming practice to simply let the application crash — you need to come up with some way to deal with errors that the application encounters.

Required error handling


LINGO

A checked exception is one that the JRE is told by the class definition to monitor. The JRE forces the user of the class to provide handling for the exception to ensure that the class performs reliably.


Java provides two kinds of exceptions: checked (those monitored by the JRE) and unchecked (those that aren’t monitored by the JRE). All the exceptions in the chapter so far are unchecked exceptions. You have the option of handling an unchecked exception. However, Java forces you to handle a checked exception. Your code won’t even compile if you try to use a method that has a checked exception associated with it.

All kinds of odd details are associated with checked and unchecked exceptions. An easy way to know whether an exception is checked is to know the parent class. All exceptions that are subclassed from the Error or RuntimeException classes are unchecked — every other exception is checked. The best practice is to handle every exception in your application, and you won’t have to worry whether an exception is checked or unchecked. A great developer always handles potential errors — that’s the bottom line.

In the following example, you create a class that relies on a checked exception. The class doesn’t actually use this exception; this is simply a demonstration of how the Catch or Specify requirement works. After you create this class, you create an application that uses the class. When you initially create the application, you do so without exception handling so you can see how the compiler reacts to the lack of exception handling. The application then adds the required exception handling and you test it out.


GO ONLINE

You really don’t need to know too many details about the whole checked and unchecked requirement except that some exceptions are checked, and the compiler will tell you if you haven’t handled them in your code. In this case, you simply add the required catch clause to your code. However, if you really do want to know how things work at a deeper level, you can read about this requirement at http://docs.oracle.com/javase/tutorial/essential/exceptions/catchOrDeclare.html. There’s a lot of controversy about required error handling. You can read a simple statement of the controversy at http://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html. Unfortunately, this short article doesn’t really discuss all the particulars of the controversy or provide you with examples. One of the best extended discussions of the topic (complete with examples) is at http://tutorials.jenkov.com/java-exceptionhandling/checked-orunchecked-exceptions.html.


Files needed: RequiredException.java and UseRequiredException.java

1. Open the editor or IDE that you’ve chosen to use for this book.

2. Type the following code into the editor screen.

// Import the required API classes.
import java.util.Scanner;
import java.util.InputMismatchException;
import java.io.IOException;

public class RequiredException
{
public void DoDisplay() throws
InputMismatchException, IOException
{
// Create the scanner.
Scanner GetInput = new Scanner(System.in);

// Ask the user for an input.
System.out.print("Type a number between 1 and 10: ");
int TheNumber = GetInput.nextInt();

// Determine if the input is in the correct range.
if ((TheNumber >= 1) && (TheNumber <= 10))

// If so, display it.
System.out.println("TheNumber = " + TheNumber);
else

// If not, throw an error.
throw new IOException(
"The value of TheNumber is: " + TheNumber);
}
}

This example doesn’t include a main() method, so you can’t execute it as an application. This class simply contains a public method called DoDisplay() that you can access from other applications. When you call DoDisplay() from another application, it obtains input from the user, determines whether the input is in the desired range, and then outputs the number or raises an exception depending on whether the user has provided the correct information.

tip.eps Notice that the method includes a new clause, throws. If you create a method that has the potential to throw an exception, you should always include the throws clause to tell other developers about the need to provide exception handling. This method can throw anInputMismatchException when the user types something other than a number. In addition, it can throw an IOException when the number is in the wrong range.

The code uses an IOException for demonstration purposes only. You really wouldn’t use this kind of exception for the error that DoDisplay() could encounter. The IOException is a checked exception, so the example uses it to demonstrate how checked exceptions work.

3. Save the code to disk using the filename RequiredException.java.

4. In your command prompt, type javac RequiredException.java and press Enter.

The compiler compiles your application and creates a .class file from it.

5. Create a new class named UseRequiredException by using the editor or IDE that you’ve chosen to use for this book.

This new class must appear in the same folder as the RequiredException class that you created in Step 2.

6. Type the following code into the editor screen.

public class UseRequiredException
{
public static void main(String[] args)
{
// Create the required object.
RequiredException ThisTest = new RequiredException();

// Use the DoDisplay() method to display a value.
ThisTest.DoDisplay();
}
}

This example simply creates an instance of the RequiredException class named ThisTest. It then uses ThisTest to access DoDisplay() to display a number onscreen.

remember.eps Notice that you don’t see any import statement in this part of the example. That’s because the RequiredException class appears in the same folder as the UseRequiredException application. When two classes appear in the same folder, you don’t have to import the first class to use it in the second class.

7. Type javac UseRequiredException.java and press Enter.

The compiler raises the error shown in Figure 8-12 to tell you that you must provide error handling for the DoDisplay() method.

9781118098783-fg0812.tif

Figure 8-12:

8. Make the following changes (shown in bold) to the UseRequiredException class.

// Import the required API classes.
import java.io.IOException;
import java.util.InputMismatchException;

public class UseRequiredException
{
public static void main(String[] args)
{
// Create the required object.
RequiredException ThisTest = new RequiredException();

// Attempt to perform the task.
try
{
// Use the DoDisplay() method to display a value.
ThisTest.DoDisplay();
}
catch (InputMismatchException | IOException e)
{
// Determine whether there is error information
// to display and output it.
if (e.getMessage() != null)
System.out.println("Please provide a value" +
" between 1 and 10!\n" + e.getMessage());
else
System.out.println("Please provide a value" +
" between 1 and 10!");
return;
}
}
}

The example now includes the required error handling. Because it’s possible to handle both exceptions using a single message, the application places both in the same catch clause.

9. Type javac UseRequiredException.java and press Enter.

The compiler compiles your application and creates a .class file from it.

10. Type java UseRequiredException and press Enter.

The application asks you to type any number.

11. Type the letter C and press Enter.

You see the expected error output. (Refer to Figure 8-9.)

12. Perform Steps 10 and 11 using the number 22 as the input.

You see the same error, but this time with some additional information. (Refer to Figure 8-10.)

13. Perform Steps 10 and 11 using the number 5 as the input.

This time the application displays the anticipated output. (Refer to Figure 8-11.)

practice_fmt.eps Modify the RequiredException class so that it relies on the Illegal
ArgumentException. Make the required changes to the UseRequired
Exception application as well. Even though the IllegalArgument
Exception isn’t a checked exception, you should still provide error handling for it.

summingup_fmt.eps Summing Up

Here are the key points you learned about in this chapter:

· Syntactical (syntax) errors normally result from writing Java code incorrectly.

· Semantic errors normally result when you write the Java code correctly but apply Java programming concepts incorrectly.

· Logical errors normally result when the Java code is both written and applied correctly, but the implementation of the task is incorrect.

· Syntactical errors are the easiest to fix, semantic errors come next, and logical errors are the hardest to fix.

· Trapping an error means detecting an exception object and doing something with it.

· Handling an error means resolving the exception by displaying a message to the user or relying on other means.

· All applications should include the appropriate error handling code.

· When providing complete error handling, always handle the most specific errors first, and then move on to less specific errors.

· Use Optional objects to help reduce the potential for errors in your application.

· Provide specific information whenever possible when throwing an error.

· Java makes it possible to catch multiple exceptions using a single catch clause.

· When the current level of the application can’t handle an exception, make sure you pass it up to the next level.

· Checked exceptions ensure that anyone using the associated method provides the required error handling.

Try-it-yourself lab

For more practice with the features covered in this chapter, try the following exercise on your own:

1. Open the UseAMenu03 application supplied with the source code for this book.

2. Fix the errors in this application.

This means removing the comments from in front of the break clauses.

3. Compile the application.

4. Run the application.

Does the application run without error?

5. Determine what sort of exception handling this application generates.

As a hint, try starting the application and simply pressing Enter at the prompt.

6. Add the required error handling.

Make sure you add generic error handling for those situations where you can’t anticipate what the user will do.

7. Compile the application.

8. Run the application.

Does the error handling work as anticipated?

Know this tech talk

· background processing: Tasks that an application performs behind the scenes. For example, when a user requests that an application print a document, the application performs this task in the background while the user continues to interact with the application in the foreground.

· call stack: A listing of the methods that preceded the current method. Each method called the next in line in order to get to the current level of the call stack. Most applications have a large number of levels, so the call stack is an essential tool in fixing application errors.

· checked exception: An exception that the JRE forces the user of a class to handle. The compiler actually checks to verify that you have provided handling for the exception and won’t create a .class file for you if you don’t provide the handling. The reason to use checked exceptions is to ensure that a class and the objects created from it perform reliably.

· error: Any unexpected or unanticipated application behavior, including actions or results that fall outside the realm of expected application output.

· error handling: The act of resolving an exception that the application has trapped by displaying a message to the user or taking other action.

· error trapping: The act of detecting an exception and passing this information to a catch statement that resolves the correct exception object.

· exception: A special object that defines an error condition within an application. The exception tells where the error has happened and what sort of error has happened. In some cases, the exception may provide additional bits of information that the recipient can use to resolve the error.

· foreground processing: Priority tasks that an application performs as part of interacting with the user (including the system). For example, the user interface for any application is a foreground processing task. In most cases, foreground processing occurs at a higher priority than background processing to ensure that the application can meet user demands in a timely manner.

· parse: The act of interpreting input and producing an output based on that input. For example, when a programmer provides code to a Java compiler, the compiler produces Java byte code as output. Likewise, when a user provides a numeric string as input, a parser can produce a numeric value as output.

· throw: The act of creating an exception object and passing it to the caller of the current code. Throwing an exception means that the current code can’t resolve the error and requires help to fix it. The exception object will help the caller understand what has happened and enable the caller to fix the problem in many situations.