Exceptions


In Lesson 4, you saw how your code generated a NullPointerException when you did something with a variable that was not properly initialized.

Exceptions are objects that represent exceptional conditions in code. You can create an Exception object and throw it. If you are aware that there might be exceptions, you can write code that explicitly deals with, or catches, them. Or, you can declare that your code chooses to not deal with exceptions, and let someone else handle the problem.

A thrown exception represents a transfer of control. You may throw an exception at any point in code; other APIs may similarly throw exceptions at any time. The VM may also throw exceptions. From the point the exception is thrown, the Java VM transfers control to the first place that deals with, or catches, the exception. If no code catches the exception, the result is abnormal program termination.[1]

[1] This is not necessarily the case when your application is executing multiple threads. See the lesson on threading.

You will ultimately need to build a user interface that allows for entry of test scores for students in a session. The user interface is where anything can go wrong: a user can type a number that is too large, they can type nothing, or they can type garbage. Your job will be to deal with invalid input as soon as it is typed in.


Test scores typed into the user interface come in as String objects. You will need to convert these strings into ints. To do so, you can use the Integer wrapper class utility method named parseInt. The parseInt method takes a String as a number and attempts to convert it to a number. If successful, parseInt returns the appropriate int. If the source String contains invalid input, the code in parseInt throws a NumberFormatException.

Start with a simple test representing a successful case:

 package sis.studentinfo; import junit.framework.TestCase; public class ScorerTest extends TestCase {    public void testCaptureScore() {       Scorer scorer = new Scorer();       assertEquals(75, scorer.score("75"));    } } 

Get this to pass:

 package sis.studentinfo; public class Scorer {    public int score(String input) {       return Integer.parseInt(input);    } } 

Then write a second test that shows what happens when invalid input is passed to the score method:

 public void testBadScoreEntered() {    Scorer scorer = new Scorer();    scorer.score("abd"); } 

This isn't the complete test, but it will demonstrate what happens when code throws an exception. Compile the code and run the tests. JUnit will report an error instead of a test failure. An error means that code within the test (or, of course, code that the test called) generated an exception that was not handled. The exception's stack trace appears in the details window in JUnit, showing that the Integer class generated a NumberFormatException.

You want your test to demonstrate that the score method generates an exception when clients pass invalid input to it. The test case documents a case for which you expect to get an exception. Thus, you want the test to pass if the exception occurs and fail if it does not.

Java provides a construct called a TRy-catch block that you use to trap exceptions. The standard form of a try-catch block contains two blocks of code. The try block consists of code that might throw an exception. The catch block contains code to execute if an exception is generated.

 public void testBadScoreEntered() {    Scorer scorer = new Scorer();    try {       scorer.score("abd");       fail("expected NumberFormatException on bad input");    }    catch (NumberFormatException success) {    } } 

The code in testBadScoreEntered presents the most common idiom used when testing for exceptions. The try block wraps the score message send, since it is the code that could generate the NumberFormatException. If the code in score generates an exception, the Java VM immediately transfers control from the point the exception was thrown to the catch block.

If execution of the code in score does not raise an exception, control proceeds normally and Java executes the next statement in the TRy block. In testBadScoreEntered, the next statement is a call to the JUnit method fail. Scorer-Test inherits fail (indirectly) from junit.framework.TestCase. Execution of fail immediately halts the test method; the VM executes no more of its code. JUnit reports the test method as a failure. Calling fail is equivalent to calling assertTrue(false) (or assertFalse(true)).

You expect score to generate an exception. If it does not, something has gone wrong, and you want to fail the test. If score does generate an exception, the fail statement is skipped, since the VM transfers control to the catch block.

The catch block is empty. Tests are about the only place where your catch blocks should ever be empty. Normally, you want to deal with a trapped exception somehow. You would do this in the catch block. In this lesson, I will present you with options for managing a caught exception.

In testBadScoreEntered, receiving an exception is a good thing. You document that by naming the NumberFormatException object in the catch clause success. Most code you will encounter will use a generic name for the exception object, such as e. Nothing says that you can't improve on this. Use an exception name to describe why you expect an exception.

The "exception test" represents what other client code will have to deal with. Somewhere in the user interface code, you will have code that you structure very similar to the code in testBadScoreEntered. The test documents the potential for score to generate a NumberFormatException and under what circumstance that potential exists.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net