📄 lib0112.html
字号:
<html>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<head>
<title>Exception-Handling Strategies</title>
<link rel="STYLESHEET" type="text/css" href="images/xpolecat.css">
<link rel="STYLESHEET" type="text/css" href="images/ie.content.css">
</head>
<body>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr><td><div STYLE="MARGIN-LEFT: 0.15in;"><a href="toc.html"><img src="images/teamlib.gif" width="62" height="15" border="0" align="absmiddle" alt="Team LiB"></a></div></td>
<td align="right"><div STYLE="MARGIN-LEFT: 0.15in;">
<a href="LiB0111.html"><img src="images/previous.gif" width="62" height="15" border="0" align="absmiddle" alt="Previous Section"></a>
<a href="LiB0113.html"><img src="images/next.gif" width="41" height="15" border="0" align="absmiddle" alt="Next Section"></a>
</div></td></tr></table>
<br>
<div class="chapter">
<a name="ch17"></a>
<div class="section">
<h2 class="first-section-title"><a name="543"></a><a name="ch17lev1sec2"></a>Exception-Handling Strategies</h2><p class="first-para">
<b class="bold">Validate all arguments explicitly in all public methods in all public classes. </b>Validating all arguments for publicly consumed methods prevents derivative exceptions. Derivative exceptions are those reported well after the error <a name="544"></a><a name="IDX-226"></a>occurred. It's an all-too-common error to pass a null argument to a method accidentally, only to find that a <span class="fixed">NullPointerException</span> was generated when the class that was called (directly or indirectly) tries to use the argument and isn't expecting the null value.</p>
<p class="para">While it's possible to get the class, method, and line number where the <span class="fixed">NullPointerException</span> occurred, the actual error occurred well before at the point where the null value originated. This often is in an entirely separate method and class from what's reported in the stack trace and can take significant time to track down, especially if the code is complex and multiple variables could have generated the exception. Typically, derivative exceptions like this take more time and effort to fix because the error message and information don't make the problem clear. Had the method generated an exception message such as "Null name argument not allowed," the error would have been easier to find and fix.</p>
<p class="para">Argument validation enables you to report an error with a clearer message than you would otherwise get. Null arguments are commonly validated. If an argument has to conform to a specific value set (for example, a <span class="fixed">docType</span> argument that allows only pdf, xls, and txt values), the value should be validated as well. I typically use <span class="fixed">java.lang.IllegalArgumentException</span> for invalid arguments, as illustrated in <a class="internaljump" href="#ch17list02">listing 17.2</a>.</p>
<div class="example">
<span class="example-title"><span class="example-titlelabel">Listing 17.2: </span>Example of Argument Checking</span><a name="545"></a><a name="ch17list02"></a>
<div class="formalbody">
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="Start example" border="0"></b></font></td>
</tr>
</table>
<pre class="literallayout">
1:public static Connection getConnection(
2: String connectionPoolName)
3: throws NamingException, SQLException
4: {
5: if (connectionPoolName == null)
6: throw new IllegalArgumentException
7: ("Null connectionPoolName not allowed.");
8: if (connectionPoolName.equals(""))
9: throw new IllegalArgumentException
10: ("Blank connectionPoolName not allowed.");
11: Context ctx = new InitialContext();
12: DataSource source = (DataSource)
13: PortableRemoteObject.narrow
14: ( ctx.lookup(connectionPoolName),
15: DataSource.class);
16: return source.getConnection();
17: }
</pre>
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="End example" border="0"></b></font></td>
</tr>
</table>
<table class="BlankSpace" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td height="16"></td>
</tr>
</table>
</div>
</div>
<p class="para">
<b class="bold">Include general catches for public methods in the deployment layer.</b> If you adopt the suggestion of throwing mostly <span class="fixed">RuntimeException</span> exceptions, <a name="546"></a><a name="IDX-227"></a>your try/catch logic will mainly be in application entry points, such as enterprise beans, servlets, RMI services, and so on. Unless you have a reason to catch errors that are more specific, I recommend a general catch of <span class="fixed">java.lang.Throwable</span>.</p>
<p class="para">This opinion is a bit controversial. Many texts promote the idea that application code should only catch exceptions it is prepared to "handle." I agree with this premise. Most texts go on to posit that an application cannot possibly have a meaningful response to a JVM error such as <span class="fixed">OutOfMemory-Exception</span> or <span class="fixed">ClassNotFoundError</span>. If you agree with this statement, logic dictates that you should not catch <span class="fixed">Throwable</span>.</p>
<p class="para">However, an application can make a meaningful response to a JVM error. That response typically is to log the error with enough context that a developer can fix the problem. If the application is a Web site or any type of multi-user application, you might also want to notify an operator or application administrator. If you don't catch JVM errors and the like, you leave the reporting of them to chance. While many containers will catch and log <span class="fixed">Throwable</span>, my experience is that those logs are too often ignored.</p>
<p class="para">Many of the applications I support are 24x7x365 with significant business ramifications if they're not functioning. I can't afford to leave the reporting (or notification) for any type of error, JVM or otherwise, to chance. I suspect that many of you can't either.</p>
<p class="para">A common solution is to catch <span class="fixed">java.lang.Exception</span> instead. However, catching <span class="fixed">java.lang.Exception</span> will miss many possible JVM errors (for example, <span class="fixed">OutOfMemoryError</span>). The cost of missing an exception is that a derivative error will probably occur. Catching <span class="fixed">java.lang.Throwable</span> is a better solution because it truly will catch everything, as shown in <a class="internaljump" href="#ch17list03">listing 17.3</a>.</p>
<div class="example">
<span class="example-title"><span class="example-titlelabel">Listing 17.3: </span>Example of Catching Throwable</span><a name="547"></a><a name="ch17list03"></a>
<div class="formalbody">
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="Start example" border="0"></b></font></td>
</tr>
</table>
<pre class="literallayout">
1:try
2:{
3: <span class="unicode">…</span> // App code here
4:}
5:catch (Throwable t)
6:{
7: _message = t.getClass().getName()
8: + ":" + t.getMessage();
9: t.printStackTrace(_log);
10:
11: _log.println("———————");
12:}
<a name="548"></a><a name="IDX-228"></a>
</pre>
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="End example" border="0"></b></font></td>
</tr>
</table>
<table class="BlankSpace" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td height="16"></td>
</tr>
</table>
</div>
</div>
<p class="para">Don't catch more specific exceptions unless your error processing is different. In cases where multiple types of checked exceptions can be thrown, I commonly see catches for each type of exception, and the code in the catch block commonly replicated for each exception type. For example, if <a class="internaljump" href="#ch17list04">listing 17.4</a> contained one catch for <span class="fixed">Throwable</span>, it would have comprised significantly less code.</p>
<div class="example">
<span class="example-title"><span class="example-titlelabel">Listing 17.4: </span>Example of Poor Exception-Catching Code</span><a name="549"></a><a name="ch17list04"></a>
<div class="formalbody">
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="Start example" border="0"></b></font></td>
</tr>
</table>
<pre class="literallayout">
1:public JMUNonStaticCodeTable
2: getAcctConslCodeTable (String aUserId,
3: String aSponsorId)
4: throws JMUException, Exception
5: {
6: try
7: {
8: <span class="unicode">…………</span> // App code here
9: }
10: catch (JMUException ne)
11: {
12: throw ne;
13: }
14: catch (Exception e)
15: {
16: throw new JMUException(
17: getJMUTransactionInfo(),
18: CLASSNAME +
19: ".getAcctConslCodeTable" +
20: "(String aUserId, "+
21: "String aSponsorId) "+
22: "Exception "+
23: e.getMessage() +
24: "obtaining accounts/consl for "+
25: "userId= "+ aUserId + "and "+
26: "sponsorId= "+ aSponsorId,
27: e);
28:
29: }<a name="550"></a><a name="IDX-229"></a>
30: catch (Throwable bigProblem)
31: {
32: throw new JMUException(
33: getJMUTransactionInfo(),
34: CLASSNAME +
35: ".getAcctConslCodeTable" +
36: "(String aUserId, "+
37: "String aSponsorId) "+
38: "THROWABLE EXCEPTION OCCURRED "+
39: "obtaining accounts/consl for "+
40: "userId= "+ aUserId + "and "+
41: "sponsorId= "+ aSponsorId,
42: bigProblem);
43: }
44: finally
45: {
46: return _acctConslCodeTable;
47: }
48: }
</pre>
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="End example" border="0"></b></font></td>
</tr>
</table>
<table class="BlankSpace" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td height="16"></td>
</tr>
</table>
</div>
</div>
<p class="para">One word of caution: if your application calls the <span class="fixed">stop()</span> method on a <span class="fixed">Thread</span>, catching <span class="fixed">Throwable</span> will also catch <span class="fixed">java.lang.ThreadDeath</span>. In this case, <span class="fixed">ThreadDeath</span> will have to be rethrown so that the <span class="fixed">Thread</span> actually dies. The <span class="fixed">stop()</span> method was deprecated early on because it's inherently unstable. Use of the <span class="fixed">stop()</span> method is not recommended and actively discouraged. If you don't stop threads with the <span class="fixed">stop()</span> method, there's no reason to worry about accidentally catching <span class="fixed">ThreadDeath</span>.</p>
<p class="para">
<a class="internaljump" href="#ch17list04">Listing 17.4</a> illustrates good as well as bad practices. Notice that the programmer did make a deliberate effort to document the context associated with the exception to help a developer debug and fix a problem later. The effort deserves some applause.</p>
<p class="para">Unfortunately, the programmer also put a return statement in the finally block on line 46. This will have the unfortunate effect of swallowing the exception. While the exception contains lots of good information, it will never be seen.</p>
<p class="para">The programmer also had the foresight to catch <span class="fixed">Throwable</span>. I view this as a good point, but some will disagree with me. However, the programmer did miss an opportunity to streamline code. The programmer has much the same processing for the <span class="fixed">Exception</span> catch as the <span class="fixed">Throwable</span> catch. The programmer could have streamlined the code by simply eliminating the <span class="fixed">Exception</span> catch. <a class="internaljump" href="#ch17list05">Listing 17.5</a> is an alternative version of <a class="internaljump" href="#ch17list04">listing 17.4</a> that corrects these problems.</p>
<div class="example">
<span class="example-title"><span class="example-titlelabel">Listing 17.5: </span>Improved Exception-Handling Code (Listing 17.4 Rewritten)</span><a name="551"></a><a name="ch17list05"></a>
<div class="formalbody">
<table class="BlueLine" border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td bgcolor="000080" class="bluecell"><font size="2" face="Arial" color="010100"><b><img src="_.gif" width="1" height="2" alt="Start example" border="0"></b></font></td>
</tr>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -