Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #12858 > unrolled thread
| Started by | Novice <novice@example..com> |
|---|---|
| First post | 2012-03-11 01:51 +0000 |
| Last post | 2012-03-13 06:05 -0300 |
| Articles | 20 on this page of 37 — 8 participants |
Back to article view | Back to comp.lang.java.programmer
Exception Handling Novice <novice@example..com> - 2012-03-11 01:51 +0000
Re: Exception Handling Lew <noone@lewscanon.com> - 2012-03-10 18:39 -0800
Re: Exception Handling Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2012-03-11 11:53 -0300
Re: Exception Handling Lew <noone@lewscanon.com> - 2012-03-11 10:51 -0700
Re: Exception Handling Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2012-03-11 16:35 -0300
Re: Exception Handling Novice <novice@example..com> - 2012-03-11 17:05 +0000
Re: Exception Handling Lew <noone@lewscanon.com> - 2012-03-11 10:53 -0700
Re: Exception Handling Novice <novice@example..com> - 2012-03-11 20:36 +0000
Re: Exception Handling Lew <noone@lewscanon.com> - 2012-03-11 11:07 -0700
Re: Exception Handling Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2012-03-11 17:00 -0300
Re: Exception Handling Novice <novice@example..com> - 2012-03-11 22:02 +0000
Re: Exception Handling Arivald <NOSPAMarivald@interia.pl> - 2012-03-11 21:03 +0100
Re: Exception Handling Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2012-03-11 18:31 -0300
Re: Exception Handling Novice <novice@example..com> - 2012-03-11 21:54 +0000
Re: Exception Handling Patricia Shanahan <pats@acm.org> - 2012-03-11 15:26 -0700
Re: Exception Handling Novice <novice@example..com> - 2012-03-11 23:23 +0000
Re: Exception Handling Lew <noone@lewscanon.com> - 2012-03-11 16:52 -0700
Re: Exception Handling Novice <novice@example..com> - 2012-03-12 17:16 +0000
Re: Exception Handling Lew <noone@lewscanon.com> - 2012-03-13 08:31 -0700
Re: Exception Handling Patricia Shanahan <pats@acm.org> - 2012-03-11 17:51 -0700
Re: Exception Handling Novice <novice@example..com> - 2012-03-12 17:26 +0000
Re: Exception Handling Arne Vajhøj <arne@vajhoej.dk> - 2012-03-12 14:49 -0400
Re: Exception Handling Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2012-03-11 20:46 -0300
Re: Exception Handling Novice <novice@example..com> - 2012-03-12 17:43 +0000
Re: Exception Handling Patricia Shanahan <pats@acm.org> - 2012-03-11 11:14 -0700
Re: Exception Handling Novice <novice@example..com> - 2012-03-11 22:35 +0000
Re: Exception Handling Lew <noone@lewscanon.com> - 2012-03-11 16:58 -0700
Re: Exception Handling Novice <novice@example..com> - 2012-03-12 15:44 +0000
Re: Exception Handling Gene Wirchenko <genew@ocis.net> - 2012-03-12 10:34 -0700
Re: Exception Handling Arivald <NOSPAMarivald@interia.pl> - 2012-03-11 20:34 +0100
Re: Exception Handling Novice <novice@example..com> - 2012-03-11 22:36 +0000
Re: Exception Handling Arne Vajhøj <arne@vajhoej.dk> - 2012-03-12 14:41 -0400
Re: Exception Handling Arne Vajhøj <arne@vajhoej.dk> - 2012-03-12 14:37 -0400
Re: Exception Handling Novice <novice@example..com> - 2012-03-12 22:43 +0000
Re: Exception Handling Lew <lewbloch@gmail.com> - 2012-03-12 16:11 -0700
Re: Exception Handling Arivald <NOSPAMarivald@interia.pl> - 2012-03-13 00:54 +0100
Re: Exception Handling Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2012-03-13 06:05 -0300
Page 1 of 2 [1] 2 Next page →
| From | Novice <novice@example..com> |
|---|---|
| Date | 2012-03-11 01:51 +0000 |
| Subject | Exception Handling |
| Message-ID | <XnsA012D42584994jpnasty@94.75.214.39> |
I've been trying to get my head around exception handling for the last
few days concurrently with my efforts to start doing logging correctly.
I've re-read the Java Tutorials section on exception handling. I read
Bloch's remarks on Exception Handling in Effective Java (2nd edition)
several days ago. I'm working my way through Stelting's Robust Java.
It's time to ask some questions to make sure I'm on the right track.
I'm struggling with the best way to revise some of my existing code.
Let's consider a concrete example and then see if we can generalize to
come up with a proper error handling strategy.
I have a utility class called LocalizationUtils which basically houses
convenience methods dealing with i18n/l10n. One of its methods is
getResources(). It expects two parameters, a String representing the
"base name" (the leading part of the resource file name) and a locale.
Here's the code for getResources() with all comments and error handling
(aside from the empty catch block) stripped out:
====================================================================
static public ResourceBundle getResources(String baseName, Locale locale
{
ResourceBundle locList = null;
try {
locList = ResourceBundle.getBundle(baseName, locale);
}
catch (MissingResourceException mrExcp) {
}
return (locList);
}
====================================================================
The program which is executing is Foo. It has a method called
getLocalizedText() which is the one executing
LocalizationUtils.getResources(). The value of the baseName is a constant
coded in an interface of constants called FooConstants which is
implemented by Foo. Here's the code for getLocalizedText() without any
error handling and just one relevant comment:
====================================================================
private void getLocalizedText() {
Locale locale = Locale.getDefault();
this.myText = LocalizationUtils.getResources(TEXT_BASE, locale);
this.myMsg = LocalizationUtils.getResources(MSG_BASE, locale);
/* Work with the localized resources. */
}
====================================================================
In terms of trouble spots, I know from experience that getResources()
will throw a MissingResourceException, which is an unchecked exception,
if the base name is misspelled. A null value in either parameter is also
going to make the getResources() method fail: ResourceBundle.getBundle()
will throw a NullPointerException if either parameter is null.
My objective is to code getResources() and getLocalizedText() as
professionally as possible. If the methods fail, I want to write a clear
message to my log and the log record needs to include a stacktrace. (I'm
assuming that a console is not necessarily available to the operators
running this program and I need to know where the error took place. Based
on an article Arved suggested in another thread,
http://www.javacodegeeks.com/2011/01/10-tips-proper-application-
logging.html, I'm inclined to minimize "position" information - class
name, method name, line number - in the log and instead get all of that
from the stacktrace.)
Now, finally, here are some questions:
Since the only exceptions I anticipate, MissingResourceException and
NullPointerException, are unchecked exceptions, I gather than I shouldn't
really do anything about them aside from logging when they happen. Okay,
fair enough; I certainly don't want to display the source code to my
user, make them enter the correct value for the baseName, make them
recompile the program and then run it again! But when/where should I log
the error? For instance, if I mess up my coding somehow and inadvertently
pass a null in the baseName, should getResources() be testing its input
parameters individually to see if they are null and write a message to
the log if they are null from within that method? I'm inclined to say yes
to that but I'm not sure what to do next. It seems pointless to carry on
with getResources() since ResourceBundle.getBundle(baseName, locale)
will fail on a NullPointerException with a null in either parameter. I
could throw a NullPointerException so that getLocalizedText() can deal
with it. But how do I get a stacktrace into the log if I follow that
strategy? It's easy enough to get the stacktrace once I've caught an
exception but I'm just talking about recognizing that an input parameter
is null; there's no exception at that point to put in my log.
If I let getResources() throw NullPointerException if either parameter is
null, then I can let getLocalizedText() catch those NullPointerExceptions
and get the stacktraces from the exception and write them to the log. In
that case, I may as well just check the input parameters for nulls, and
simply throw NullPointerException with a specific message within
getResources(); then getLocalizedText() can have a try/catch block. The
try/catch can detect the NullPointerException and write both the message
and the stacktrace to the log.
But I gather that you should handle the error as close to where it
happened as possible when you can. I'd tend to prefer to handle the null
parameter values in getResources() except that I'm not sure how to write
the stack trace to the log before any exception has happened.
One other questions. When, if ever, should I execute System.exit() with a
non-zero integer? In my example, I know that program Foo can't proceed
without the resources it is trying to get in getResources() so if I
simply throw exceptions and write to the log and then let the program
keep going, I'm simply going to get another NullPointerException on the
first statement that tries to use the resources. I'm thinking that I
should do a System.exit(1) after I've logged a null parameter or in the
event of a MissingResourceException in getResources(). But I have yet to
see System.exit() used in ANY example of error handling in any resource
I've looked at so far.
--
Novice
[toc] | [next] | [standalone]
| From | Lew <noone@lewscanon.com> |
|---|---|
| Date | 2012-03-10 18:39 -0800 |
| Message-ID | <jjh39f$crc$1@news.albasani.net> |
| In reply to | #12858 |
Novice wrote:
snip
> I have a utility class called LocalizationUtils which basically houses
> convenience methods dealing with i18n/l10n. One of its methods is
> getResources(). It expects two parameters, a String representing the
> "base name" (the leading part of the resource file name) and a locale.
>
> Here's the code for getResources() with all comments and error handling
> (aside from the empty catch block) stripped out:
>
> ====================================================================
> static public ResourceBundle getResources(String baseName, Locale locale
> {
> ResourceBundle locList = null;
Don't use throwaway initializations, usually.
> try {
> locList = ResourceBundle.getBundle(baseName, locale);
> }
> catch (MissingResourceException mrExcp) {
Log and return 'null' if that's the recovery strategy for this exception.
> }
>
> return (locList);
> }
> ====================================================================
>
> The program which is executing is Foo. It has a method called
> getLocalizedText() which is the one executing
> LocalizationUtils.getResources(). The value of the baseName is a constant
> coded in an interface of constants called FooConstants which is
> implemented by Foo. Here's the code for getLocalizedText() without any
> error handling and just one relevant comment:
Using an interface to define constants is the "Constant Interface
Antipattern". (Google it.) Use a class to define constants, not an interface.
An interface is there to define a type. Using it merely to define constants
violates the spirit of interfaces, which is to avoid implementation.
> ====================================================================
> private void getLocalizedText() {
>
> Locale locale = Locale.getDefault();
>
> this.myText = LocalizationUtils.getResources(TEXT_BASE, locale);
> this.myMsg = LocalizationUtils.getResources(MSG_BASE, locale);
>
> /* Work with the localized resources. */
> }
> ====================================================================
>
> In terms of trouble spots, I know from experience that getResources()
> will throw a MissingResourceException, which is an unchecked exception,
> if the base name is misspelled. A null value in either parameter is also
> going to make the getResources() method fail: ResourceBundle.getBundle()
> will throw a NullPointerException if either parameter is null.
>
> My objective is to code getResources() and getLocalizedText() as
> professionally as possible. If the methods fail, I want to write a clear
> message to my log and the log record needs to include a stacktrace. (I'm
example:
logger.error(message, exception);
> assuming that a console is not necessarily available to the operators
> running this program and I need to know where the error took place. Based
> on an article Arved suggested in another thread,
> http://www.javacodegeeks.com/2011/01/10-tips-proper-application-
> logging.html, I'm inclined to minimize "position" information - class
> name, method name, line number - in the log and instead get all of that
> from the stacktrace.)
I disagree.
I'd keep that class/method info in the log message. Line information is less
valuable unless your methods are far, far too long.
> Now, finally, here are some questions:
>
> Since the only exceptions I anticipate, MissingResourceException and
> NullPointerException, are unchecked exceptions, I gather than I shouldn't
> really do anything about them aside from logging when they happen. Okay,
I disagree. You should end the program gracefully and get someone to fix the
programming error right away.
> fair enough; I certainly don't want to display the source code to my
> user, make them enter the correct value for the baseName, make them
> recompile the program and then run it again! But when/where should I log
> the error? For instance, if I mess up my coding somehow and inadvertently
In the log file.
> pass a null in the baseName, should getResources() be testing its input
> parameters individually to see if they are null and write a message to
> the log if they are null from within that method? I'm inclined to say yes
Always check all parameters for validity, either by an explicit check for a
public or protected method, or by controlling what's passed to package-private
or private methods.
A normal practice is to have an application-specific checked exception to
throw, or to throw the standard unchecked exception. For example:
if (argument == null)
{
final String msg = "null argument";
IllegalArgumentException except = new IllegalArgumentException(msg);
logger.error(msg, except);
throw except;
}
or similarly for application checked exception 'FooException'.
throw new FooException(new IllegalArgumentException(msg));
Somewhere up the stack you should catch the exception and convert it to valid
program state"
catch(RuntimeException except)
{
forwardProgramControlToErrorScreen();
}
> to that but I'm not sure what to do next. It seems pointless to carry on
> with getResources() since ResourceBundle.getBundle(baseName, locale)
> will fail on a NullPointerException with a null in either parameter. I
> could throw a NullPointerException so that getLocalizedText() can deal
> with it. But how do I get a stacktrace into the log if I follow that
> strategy? It's easy enough to get the stacktrace once I've caught an
> exception but I'm just talking about recognizing that an input parameter
> is null; there's no exception at that point to put in my log.
There is if you create one. That's why Java has the 'new' operator.
> If I let getResources() throw NullPointerException if either parameter is
Better, use 'IllegalArgumentException'.
> null, then I can let getLocalizedText() catch those NullPointerExceptions
> and get the stacktraces from the exception and write them to the log. In
> that case, I may as well just check the input parameters for nulls, and
> simply throw NullPointerException with a specific message within
'IllegalArgumentException'.
> getResources(); then getLocalizedText() can have a try/catch block. The
> try/catch can detect the NullPointerException and write both the message
> and the stacktrace to the log.
Write the log at the point where you detect the error, not only further up the
stack.
> But I gather that you should handle the error as close to where it
> happened as possible when you can. I'd tend to prefer to handle the null
> parameter values in getResources() except that I'm not sure how to write
> the stack trace to the log before any exception has happened.
IllegalArgumentException exception = new IllegalArgumentException(msg);
logger.error("Unable to proceed", exception);
> One other questions. When, if ever, should I execute System.exit() with a
> non-zero integer? In my example, I know that program Foo can't proceed
Never. Program exit should be under user control.
> without the resources it is trying to get in getResources() so if I
> simply throw exceptions and write to the log and then let the program
> keep going, I'm simply going to get another NullPointerException on the
> first statement that tries to use the resources. I'm thinking that I
> should do a System.exit(1) after I've logged a null parameter or in the
> event of a MissingResourceException in getResources(). But I have yet to
> see System.exit() used in ANY example of error handling in any resource
> I've looked at so far.
Hmm.
--
Lew
Honi soit qui mal y pense.
http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
[toc] | [prev] | [next] | [standalone]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2012-03-11 11:53 -0300 |
| Message-ID | <h%27r.13665$HX7.8681@newsfe11.iad> |
| In reply to | #12859 |
On 12-03-10 10:39 PM, Lew wrote: > Novice wrote: [ SNIP ] >> My objective is to code getResources() and getLocalizedText() as >> professionally as possible. If the methods fail, I want to write a clear >> message to my log and the log record needs to include a stacktrace. (I'm > > example: > > logger.error(message, exception); > >> assuming that a console is not necessarily available to the operators >> running this program and I need to know where the error took place. Based >> on an article Arved suggested in another thread, >> http://www.javacodegeeks.com/2011/01/10-tips-proper-application- >> logging.html, I'm inclined to minimize "position" information - class >> name, method name, line number - in the log and instead get all of that >> from the stacktrace.) > > I disagree. > > I'd keep that class/method info in the log message. Line information is > less valuable unless your methods are far, far too long. We may be talking/thinking at cross-purposes here: you, me, the article author, and Novice. The logging article author states that you should never include file name, class name, or line number. To be accurate the article is an edited compilation of what another fellow (Tomasz Nurkiewicz) has written about logging: I haven't been able to find the originals to see what Tomasz put forth as explanation for this stance. Further, and presumably this also comes from Tomasz, it's stated that "logging class name, method name and/or line number has a serious performance impact." Now, to be fair to him this is also still promulgated by Ceki Gulcu's log4j documentation. I suspect that in recent years with newer JVMs that the performance impact of some of the position conversion specifiers is considerably less than it was when the warnings were first issued. Having said that, *my* argument against regularly using source position information is motivated by retaining clarity of logs. Try reading logs in a text editor or on the console when the first part of every entry is not only level and timestamp and thread ID but also FQ classname, methodname, and line number. That positional info is irrelevant almost all the time, and yet a _default_ decision to include it seriously clutters logs. The info you really want starts halfway across the editor window. The human eye is also not that great at differentiating one blob of letters from another; ignoring the level and timestamp is easy (they "look" different when scanning), but the positional info easily runs together with the real message. My position is, if you need it, include it. Don't default (let's say through PatternLayout strings) to having it uniformly. Bear in mind (if performance is still any kind of concern) that the log4j %c conversion specifier gives you classname for free if you're creating loggers by class. You don't need it for errors, not if you're dumping stacktraces. You surely don't need it for info or warnings. Debug may or may not benefit from positional information, but that should be case by case, and if you do need a debug statement to include positional info, what's so tough about putting it in that one, specific debug message? >> Now, finally, here are some questions: >> >> Since the only exceptions I anticipate, MissingResourceException and >> NullPointerException, are unchecked exceptions, I gather than I shouldn't >> really do anything about them aside from logging when they happen. Okay, > > I disagree. You should end the program gracefully and get someone to fix > the programming error right away. > [ SNIP ] Not often in the real world can you do that, Lew. And you know it. One source of work like this (fixing errors) for ops support and maintenance programmers is operational problem reports (trouble tickets etc) detected and entered by business. Another is ops support monitoring (Splunk, say) of logs...in which case something they detect may also enter the ticket/defect tracking systems. Unless something is truly critical nobody is going to shut down a 24/7 public-facing or partner-supporting (b2b) system just because a programming error popped up as a runtime exception. In fact, in the absence of any problem reports from the field an issue like that might well end up as a low/medium severity, low/medium priority defect - mixed in with dozens or hundreds of others - that'll get handled a few weeks or months later. AHS -- Last week I helped my friend stay put. It's a lot easier'n helpin' 'em move. I just went over to his house and made sure that he did not start to load shit into a truck. -- Mitch Hedberg
[toc] | [prev] | [next] | [standalone]
| From | Lew <noone@lewscanon.com> |
|---|---|
| Date | 2012-03-11 10:51 -0700 |
| Message-ID | <jjionk$l5q$1@news.albasani.net> |
| In reply to | #12860 |
Arved Sandstrom wrote: > Lew wrote: > [ SNIP ] > We may be talking/thinking at cross-purposes here: you, me, the article > author, and Novice. The logging article author states that you should > never include file name, class name, or line number. To be accurate the > article is an edited compilation of what another fellow (Tomasz > Nurkiewicz) has written about logging: I haven't been able to find the > originals to see what Tomasz put forth as explanation for this stance. > > Further, and presumably this also comes from Tomasz, it's stated that > "logging class name, method name and/or line number has a serious > performance impact." Now, to be fair to him this is also still > promulgated by Ceki Gulcu's log4j documentation. > > I suspect that in recent years with newer JVMs that the performance > impact of some of the position conversion specifiers is considerably > less than it was when the warnings were first issued. > > Having said that, *my* argument against regularly using source position > information is motivated by retaining clarity of logs. Try reading logs > in a text editor or on the console when the first part of every entry is > not only level and timestamp and thread ID but also FQ classname, > methodname, and line number. That positional info is irrelevant almost > all the time, and yet a _default_ decision to include it seriously > clutters logs. The info you really want starts halfway across the editor > window. The human eye is also not that great at differentiating one blob > of letters from another; ignoring the level and timestamp is easy (they > "look" different when scanning), but the positional info easily runs > together with the real message. > > My position is, if you need it, include it. Don't default (let's say > through PatternLayout strings) to having it uniformly. Bear in mind (if > performance is still any kind of concern) that the log4j %c conversion > specifier gives you classname for free if you're creating loggers by > class. You don't need it for errors, not if you're dumping stacktraces. > You surely don't need it for info or warnings. Debug may or may not > benefit from positional information, but that should be case by case, > and if you do need a debug statement to include positional info, what's > so tough about putting it in that one, specific debug message? I see. Good points. >> I disagree. You should end the program gracefully and get someone to fix >> the programming error right away. >> > [ SNIP ] > > Not often in the real world can you do that, Lew. And you know it. One At another point in that post, not cited, I talk about not ending the program but, "Somewhere up the stack you should catch the exception and convert it to valid program state." You are right that that is often not ending the program. As I also said in that post, in answer to when the program should abend, "Never. Program exit should be under user control." So I agree with you. > source of work like this (fixing errors) for ops support and maintenance > programmers is operational problem reports (trouble tickets etc) > detected and entered by business. Another is ops support monitoring > (Splunk, say) of logs...in which case something they detect may also > enter the ticket/defect tracking systems. > > Unless something is truly critical nobody is going to shut down a 24/7 > public-facing or partner-supporting (b2b) system just because a > programming error popped up as a runtime exception. In fact, in the > absence of any problem reports from the field an issue like that might > well end up as a low/medium severity, low/medium priority defect - mixed > in with dozens or hundreds of others - that'll get handled a few weeks > or months later. As I also stated. In the cases you state, "exiting gracefully" means "when the operator says so". There is nothing in my statements to gainsay your points. /Au contraire/, I spoke against exceptions crashing or stopping a program. And you know it. -- Lew Honi soit qui mal y pense. http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
[toc] | [prev] | [next] | [standalone]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2012-03-11 16:35 -0300 |
| Message-ID | <G777r.7791$v11.4979@newsfe20.iad> |
| In reply to | #12864 |
On 12-03-11 02:51 PM, Lew wrote: > Arved Sandstrom wrote: [ SNIP ] >> Unless something is truly critical nobody is going to shut down a 24/7 >> public-facing or partner-supporting (b2b) system just because a >> programming error popped up as a runtime exception. In fact, in the >> absence of any problem reports from the field an issue like that might >> well end up as a low/medium severity, low/medium priority defect - mixed >> in with dozens or hundreds of others - that'll get handled a few weeks >> or months later. > > As I also stated. > > In the cases you state, "exiting gracefully" means "when the operator > says so". There is nothing in my statements to gainsay your points. /Au > contraire/, I spoke against exceptions crashing or stopping a program. > > And you know it. > Fair enough: we agree. The point I was making was mostly for the OP, and really does boil down to making it clear that often "exit gracefully" means "when the operator says so", not having the application programmed to automatically exit gracefully. I think it's valid in the OP's case to make that distinction, seeing as how he's wondering why he hasn't seen more System.exit calls. AHS -- Last week I helped my friend stay put. It's a lot easier'n helpin' 'em move. I just went over to his house and made sure that he did not start to load shit into a truck. -- Mitch Hedberg
[toc] | [prev] | [next] | [standalone]
| From | Novice <novice@example..com> |
|---|---|
| Date | 2012-03-11 17:05 +0000 |
| Message-ID | <XnsA01385245AD09jpnasty@94.75.214.39> |
| In reply to | #12859 |
Lew <noone@lewscanon.com> wrote in news:jjh39f$crc$1@news.albasani.net:
> Novice wrote:
> snip
>> I have a utility class called LocalizationUtils which basically
>> houses convenience methods dealing with i18n/l10n. One of its methods
>> is getResources(). It expects two parameters, a String representing
>> the "base name" (the leading part of the resource file name) and a
>> locale.
>>
>> Here's the code for getResources() with all comments and error
>> handling (aside from the empty catch block) stripped out:
>>
>> ====================================================================
>> static public ResourceBundle getResources(String baseName, Locale
>> locale {
>> ResourceBundle locList = null;
>
> Don't use throwaway initializations, usually.
>
Why?
If I omit that line and simply use the following in the try block:
ResourceBundle locList = ResourceBundle.getBundle(baseName, locale);
locList isn't visible after the try/catch so that I can return it.
>> try {
>> locList = ResourceBundle.getBundle(baseName, locale);
>> }
>> catch (MissingResourceException mrExcp) {
>
> Log and return 'null' if that's the recovery strategy for this
> exception.
>
Is that what I should do, return null if there is a problem getting the
resource?
I'm not sure if I should be returning anything at all. Maybe I should
just log and stop the program?
>> }
>>
>> return (locList);
>> }
>> ====================================================================
>>
>> The program which is executing is Foo. It has a method called
>> getLocalizedText() which is the one executing
>> LocalizationUtils.getResources(). The value of the baseName is a
>> constant coded in an interface of constants called FooConstants which
>> is implemented by Foo. Here's the code for getLocalizedText() without
>> any error handling and just one relevant comment:
>
> Using an interface to define constants is the "Constant Interface
> Antipattern". (Google it.) Use a class to define constants, not an
> interface.
>
> An interface is there to define a type. Using it merely to define
> constants violates the spirit of interfaces, which is to avoid
> implementation.
>
Fair enough. I've converted each constants interface to a class with a
private constructor that throws an exception if someone tries to
instantiate it.
>> ====================================================================
>> private void getLocalizedText() {
>>
>> Locale locale = Locale.getDefault();
>>
>> this.myText = LocalizationUtils.getResources(TEXT_BASE, locale);
>> this.myMsg = LocalizationUtils.getResources(MSG_BASE, locale);
>>
>> /* Work with the localized resources. */
>> }
>> ====================================================================
>>
>> In terms of trouble spots, I know from experience that getResources()
>> will throw a MissingResourceException, which is an unchecked
>> exception, if the base name is misspelled. A null value in either
>> parameter is also going to make the getResources() method fail:
>> ResourceBundle.getBundle() will throw a NullPointerException if
>> either parameter is null.
>>
>> My objective is to code getResources() and getLocalizedText() as
>> professionally as possible. If the methods fail, I want to write a
>> clear message to my log and the log record needs to include a
>> stacktrace. (I'm
>
> example:
>
> logger.error(message, exception);
>
Exactly the kind of thing I had in mind.
>> assuming that a console is not necessarily available to the operators
>> running this program and I need to know where the error took place.
>> Based on an article Arved suggested in another thread,
>> http://www.javacodegeeks.com/2011/01/10-tips-proper-application-
>> logging.html, I'm inclined to minimize "position" information - class
>> name, method name, line number - in the log and instead get all of
>> that from the stacktrace.)
>
> I disagree.
>
> I'd keep that class/method info in the log message. Line information
> is less valuable unless your methods are far, far too long.
>
Tip 6 in the article makes the point that it is redundant and expensive
to get class, method and line information if it is already in the log
message. A stacktrace will tell me all of that and more so shouldn't I be
concentrating on getting a stacktrace, plus whatever I'll need that isn't
in the stacktrace, like the date and time of the problem?
>> Now, finally, here are some questions:
>>
>> Since the only exceptions I anticipate, MissingResourceException and
>> NullPointerException, are unchecked exceptions, I gather than I
>> shouldn't really do anything about them aside from logging when they
>> happen. Okay,
>
> I disagree. You should end the program gracefully and get someone to
> fix the programming error right away.
>
But what's the right way to end the program? System.exit()? That seems
the obvious way but as I've said further down, that doesn't seem to be
the method used in the books and articles I've been reading. What's the
better way?
>> fair enough; I certainly don't want to display the source code to my
>> user, make them enter the correct value for the baseName, make them
>> recompile the program and then run it again! But when/where should I
>> log the error? For instance, if I mess up my coding somehow and
>> inadvertently
>
> In the log file.
>
Yes, I realize that it goes in the log file. I mean when and where in my
code do I do that? In getResource() or getLocalizedText()?
>> pass a null in the baseName, should getResources() be testing its
>> input parameters individually to see if they are null and write a
>> message to the log if they are null from within that method? I'm
>> inclined to say yes
>
> Always check all parameters for validity, either by an explicit check
> for a public or protected method, or by controlling what's passed to
> package-private or private methods.
>
> A normal practice is to have an application-specific checked exception
> to throw, or to throw the standard unchecked exception. For example:
>
> if (argument == null)
> {
> final String msg = "null argument";
> IllegalArgumentException except = new
> IllegalArgumentException(msg); logger.error(msg, except);
> throw except;
> }
>
> or similarly for application checked exception 'FooException'.
>
> throw new FooException(new IllegalArgumentException(msg));
>
At least one of the articles/books recommended against creating custom
exceptions unless necessary, preferring to use existing exceptions where
possible.
The Java Tutorial puts it this way:
"You should write your own exception classes if you answer yes to any of
the following questions; otherwise, you can probably use someone else's.
- Do you need an exception type that isn't represented by those in the
Java platform?
- Would it help users if they could differentiate your exceptions from
those thrown by classes written by other vendors?
- Does your code throw more than one related exception?
- If you use someone else's exceptions, will users have access to those
exceptions? A similar question is, should your package be independent and
self-contained?"
I don't _think_ I qualify to create my own exception under any of these
conditions so I'm inclined to stay with the standard ones. Or am I
missing something?
Assuming I'm not, I'm inclined to use the first approach you suggested.
Or perhaps use the technique but throw a NullPointerException. Bloch
implied that IllegalArgumentException was fine for bad values but that
NullPointerException was preferred where a parameter had a null value.
> Somewhere up the stack you should catch the exception and convert it
> to valid program state"
>
> catch(RuntimeException except)
> {
> forwardProgramControlToErrorScreen();
> }
>
I went into Eclipse for a minute and amended getResources() to look like
this:
========================================================================
static public ResourceBundle getResources(String baseName, Locale locale)
throws NullPointerException, IllegalArgumentException {
if (baseName == null) {
final String msg = "The base name cannot be null.";
NullPointerException nullPointerException = new NullPointerException
(msg);
Logger logger = Logger.getLogger(CLASS_NAME);
logger.log(Level.SEVERE, msg, nullPointerException);
throw nullPointerException;
}
if (locale == null) {
final String msg = "The locale cannot be null."; //$NON-NLS-1$
NullPointerException nullPointerException = new NullPointerException
(msg);
Logger logger = Logger.getLogger(CLASS_NAME);
logger.log(Level.SEVERE, msg, nullPointerException);
throw nullPointerException;
}
//ResourceBundle resourceFile = null;
try {
ResourceBundle resourceFile = ResourceBundle.getBundle(baseName,
locale);
return(resourceFile);
}
catch (MissingResourceException mrExcp) {
String msg = "Unable to find resources for base name, " + baseName + ",
and locale, " + locale + ". Check the spelling of the base name.";
throw new IllegalArgumentException(msg);
}
}
========================================================================
That works just fine and my exception, with stacktrace, is logged before
I've left getResources(). But why am I throwing the exception at the end
of the if (baseName == null) block? Why not just exit the program
gracefully instead of throwing the exception? If I pass it back up to the
caller, what is is actually supposed to do, given that the message has
been logged and recovery is not practical? Am I only passing it up so
that getLocalizedText() can stop the program?
>> to that but I'm not sure what to do next. It seems pointless to carry
>> on with getResources() since ResourceBundle.getBundle(baseName,
>> locale) will fail on a NullPointerException with a null in either
>> parameter. I could throw a NullPointerException so that
>> getLocalizedText() can deal with it. But how do I get a stacktrace
>> into the log if I follow that strategy? It's easy enough to get the
>> stacktrace once I've caught an exception but I'm just talking about
>> recognizing that an input parameter is null; there's no exception at
>> that point to put in my log.
>
> There is if you create one. That's why Java has the 'new' operator.
>
Yes, I see that from your technique of creating one. I hadn't anticipated
that approach.
>> If I let getResources() throw NullPointerException if either
>> parameter is
>
> Better, use 'IllegalArgumentException'.
>
>> null, then I can let getLocalizedText() catch those
>> NullPointerExceptions and get the stacktraces from the exception and
>> write them to the log. In that case, I may as well just check the
>> input parameters for nulls, and simply throw NullPointerException
>> with a specific message within
>
> 'IllegalArgumentException'.
>
I have no strong feelings about this one way or the other but Bloch, on
page 248 of Effective Java (2nd edition) says: "Arguably, all erroneous
method invocations boil down to an illegal argument or an illegal state,
but other exceptions are standardly used for certain kinds of illegal
arguments and states. If a caller passes null in some parameter for which
null values are prohibited, convention dictates that NullPointerException
be thrown rather than IllegalArgumentException."
Can we agree that whether I use IllegalArgumentException or
NullPointerException in the situation I'm describing in my own code is
simply a matter of personal style or preference? Or is there a reason to
prefer IllegalArgumentException that Bloch failed to consider?
Like I said, I'm fine with either approach.
>> getResources(); then getLocalizedText() can have a try/catch block.
>> The try/catch can detect the NullPointerException and write both the
>> message and the stacktrace to the log.
>
> Write the log at the point where you detect the error, not only
> further up the stack.
>
That's what I wanted to do. I just wasn't sure how to get the stacktrace
into the log until you showed me that technique ;-)
>> But I gather that you should handle the error as close to where it
>> happened as possible when you can. I'd tend to prefer to handle the
>> null parameter values in getResources() except that I'm not sure how
>> to write the stack trace to the log before any exception has
>> happened.
>
> IllegalArgumentException exception = new
> IllegalArgumentException(msg); logger.error("Unable to proceed",
> exception);
>
>> One other questions. When, if ever, should I execute System.exit()
>> with a non-zero integer? In my example, I know that program Foo can't
>> proceed
>
> Never. Program exit should be under user control.
>
So, given that my application has a GUI, leave the application suspended
at the exception and make the user click the Close button? Why is that
better than just exiting given that the program can't proceed without the
missing resources in this case?
If this were a batch program rather than one with a GUI, would we close
with System.exit()? Or wait for the operator to notice the program is
suspended and make him kill it?
>> without the resources it is trying to get in getResources() so if I
>> simply throw exceptions and write to the log and then let the program
>> keep going, I'm simply going to get another NullPointerException on
>> the first statement that tries to use the resources. I'm thinking
>> that I should do a System.exit(1) after I've logged a null parameter
>> or in the event of a MissingResourceException in getResources(). But
>> I have yet to see System.exit() used in ANY example of error handling
>> in any resource I've looked at so far.
>
> Hmm.
>
--
Novice
[toc] | [prev] | [next] | [standalone]
| From | Lew <noone@lewscanon.com> |
|---|---|
| Date | 2012-03-11 10:53 -0700 |
| Message-ID | <jjiorj$l5q$2@news.albasani.net> |
| In reply to | #12862 |
Novice wrote:
> Lew wrote:
>> Novice wrote:
>> [snip]
>>> I have a utility class called LocalizationUtils which basically
>>> houses convenience methods dealing with i18n/l10n. One of its methods
>>> is getResources(). It expects two parameters, a String representing
>>> the "base name" (the leading part of the resource file name) and a
>>> locale.
>>>
>>> Here's the code for getResources() with all comments and error
>>> handling (aside from the empty catch block) stripped out:
>>>
>>> ====================================================================
>>> static public ResourceBundle getResources(String baseName, Locale
>>> locale {
>>> ResourceBundle locList = null;
>>
>> Don't use throwaway initializations, usually.
>>
> Why?
>
> If I omit that line and simply use the following in the try block:
>
> ResourceBundle locList = ResourceBundle.getBundle(baseName, locale);
>
> locList isn't visible after the try/catch so that I can return it.
Well, I didn't recommend that either. There are so many ways to avoid
redundant initialization. So - what could avoid the redundant initialization
without the pitfall you cite?
--
Lew
Honi soit qui mal y pense.
http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
[toc] | [prev] | [next] | [standalone]
| From | Novice <novice@example..com> |
|---|---|
| Date | 2012-03-11 20:36 +0000 |
| Message-ID | <XnsA013A90663692jpnasty@94.75.214.39> |
| In reply to | #12865 |
Lew <noone@lewscanon.com> wrote in news:jjiorj$l5q$2@news.albasani.net:
> Novice wrote:
>> Lew wrote:
>>> Novice wrote:
>>> [snip]
>>>> I have a utility class called LocalizationUtils which basically
>>>> houses convenience methods dealing with i18n/l10n. One of its
>>>> methods is getResources(). It expects two parameters, a String
>>>> representing the "base name" (the leading part of the resource file
>>>> name) and a locale.
>>>>
>>>> Here's the code for getResources() with all comments and error
>>>> handling (aside from the empty catch block) stripped out:
>>>>
>>>> ====================================================================
>>>> static public ResourceBundle getResources(String baseName, Locale
>>>> locale {
>>>> ResourceBundle locList = null;
>>>
>>> Don't use throwaway initializations, usually.
>>>
>> Why?
>>
>> If I omit that line and simply use the following in the try block:
>>
>> ResourceBundle locList = ResourceBundle.getBundle(baseName, locale);
>>
>> locList isn't visible after the try/catch so that I can return it.
>
> Well, I didn't recommend that either. There are so many ways to avoid
> redundant initialization. So - what could avoid the redundant
> initialization without the pitfall you cite?
>
I see that Arivald has answered that already in his contributions to the
thread ;-)
I'll use one of his approaches.
--
Novice
[toc] | [prev] | [next] | [standalone]
| From | Lew <noone@lewscanon.com> |
|---|---|
| Date | 2012-03-11 11:07 -0700 |
| Message-ID | <jjipli$np7$1@news.albasani.net> |
| In reply to | #12862 |
Novice wrote:
> Lew wrote:
>> Novice wrote:
>> snip
>>> try {
>>> locList = ResourceBundle.getBundle(baseName, locale);
>>> }
>>> catch (MissingResourceException mrExcp) {
>>
>> Log and return 'null' if that's the recovery strategy for this
>> exception.
>>
> Is that what I should do, return null if there is a problem getting the
> resource?
>
> I'm not sure if I should be returning anything at all. Maybe I should
> just log and stop the program?
I said *if* that's the strategy. What do you think? It may depend on the
specifics of the case.
> Fair enough. I've converted each constants interface to a class with a
> private constructor that throws an exception if someone tries to
> instantiate it.
How would that exception ever occur? How could "someone" ever try to call a
private constructor?
Don't throw code into a program that is provably never called.
> Tip 6 in the article makes the point that it is redundant and expensive
We've discussed this before, remember?
It's not expensive. When you're calling a logger statement for an error, the
cost of the error SWAMPS the time in the logger. Think about it.
> to get class, method and line information if it is already in the log
> message. A stacktrace will tell me all of that and more so shouldn't I be
> concentrating on getting a stacktrace, plus whatever I'll need that isn't
> in the stacktrace, like the date and time of the problem?
There are many who have answered this question, in response to your questions.
The answers covered a lot of approaches. Perhaps you recall them.
>>> Now, finally, here are some questions:
>>>
>>> Since the only exceptions I anticipate, MissingResourceException and
>>> NullPointerException, are unchecked exceptions, I gather than I
>>> shouldn't really do anything about them aside from logging when they
>>> happen. Okay,
>>
>> I disagree. You should end the program gracefully and get someone to
>> fix the programming error right away.
>>
> But what's the right way to end the program? System.exit()? That seems
Under operator control.
> the obvious way but as I've said further down, that doesn't seem to be
> the method used in the books and articles I've been reading. What's the
> better way?
Under operator control.
>>> fair enough; I certainly don't want to display the source code to my
>>> user, make them enter the correct value for the baseName, make them
>>> recompile the program and then run it again! But when/where should I
>>> log the error? For instance, if I mess up my coding somehow and
>>> inadvertently
>>
>> In the log file.
>>
> Yes, I realize that it goes in the log file. I mean when and where in my
> code do I do that? In getResource() or getLocalizedText()?
Wherever you detect the error.
>>> pass a null in the baseName, should getResources() be testing its
>>> input parameters individually to see if they are null and write a
>>> message to the log if they are null from within that method? I'm
>>> inclined to say yes
>>
>> Always check all parameters for validity, either by an explicit check
>> for a public or protected method, or by controlling what's passed to
>> package-private or private methods.
>>
>> A normal practice is to have an application-specific checked exception
>> to throw, or to throw the standard unchecked exception. For example:
>>
>> if (argument == null)
>> {
>> final String msg = "null argument";
>> IllegalArgumentException except = new
>> IllegalArgumentException(msg); logger.error(msg, except);
>> throw except;
>> }
>>
>> or similarly for application checked exception 'FooException'.
>>
>> throw new FooException(new IllegalArgumentException(msg));
>>
> At least one of the articles/books recommended against creating custom
> exceptions unless necessary, preferring to use existing exceptions where
> possible.
>
> The Java Tutorial puts it this way:
>
> "You should write your own exception classes if you answer yes to any of
> the following questions; otherwise, you can probably use someone else's.
>
> - Do you need an exception type that isn't represented by those in the
> Java platform?
> - Would it help users if they could differentiate your exceptions from
> those thrown by classes written by other vendors?
> - Does your code throw more than one related exception?
> - If you use someone else's exceptions, will users have access to those
> exceptions? A similar question is, should your package be independent and
> self-contained?"
>
> I don't _think_ I qualify to create my own exception under any of these
> conditions so I'm inclined to stay with the standard ones. Or am I
> missing something?
Yes.
It is common and frequently useful to create an application-specific checked
exception. Again, and I've said this many times, think about what will be
useful when troubleshooting a problem. Many times, a custom exception is
useful. It says that the underlying exception has been caught, logged and wrapped.
Runtime exceptions are dangerous because they slip past you. If you catch them
in a custom checked exception then code must handle it. All those runtime
exceptions are related, by dint of being exceptions within the same
application. BOOM! Qualified.
> Assuming I'm not, I'm inclined to use the first approach you suggested.
> Or perhaps use the technique but throw a NullPointerException. Bloch
> implied that IllegalArgumentException was fine for bad values but that
> NullPointerException was preferred where a parameter had a null value.
That's his opinion.
Many others think that 'IllegalArgumentException' makes more sense if it's an
argument that has an illegal value.
What do you think?
>> Somewhere up the stack you should catch the exception and convert it
>> to valid program state"
>>
>> catch(RuntimeException except)
>> {
>> forwardProgramControlToErrorScreen();
>> }
>>
> I went into Eclipse for a minute and amended getResources() to look like
> this:
>
> ========================================================================
> static public ResourceBundle getResources(String baseName, Locale locale)
> throws NullPointerException, IllegalArgumentException {
>
> if (baseName == null) {
> final String msg = "The base name cannot be null.";
> NullPointerException nullPointerException = new NullPointerException
> (msg);
> Logger logger = Logger.getLogger(CLASS_NAME);
> logger.log(Level.SEVERE, msg, nullPointerException);
> throw nullPointerException;
> }
>
> if (locale == null) {
> final String msg = "The locale cannot be null."; //$NON-NLS-1$
> NullPointerException nullPointerException = new NullPointerException
> (msg);
> Logger logger = Logger.getLogger(CLASS_NAME);
> logger.log(Level.SEVERE, msg, nullPointerException);
> throw nullPointerException;
Kind of a bad name for the variable, there.
What does your log look like with 'msg' printed twice?
> }
>
> //ResourceBundle resourceFile = null;
>
> try {
> ResourceBundle resourceFile = ResourceBundle.getBundle(baseName,
> locale);
> return(resourceFile);
> }
> catch (MissingResourceException mrExcp) {
> String msg = "Unable to find resources for base name, " + baseName + ",
> and locale, " + locale + ". Check the spelling of the base name.";
> throw new IllegalArgumentException(msg);
> }
> }
> ========================================================================
>
> That works just fine and my exception, with stacktrace, is logged before
> I've left getResources(). But why am I throwing the exception at the end
> of the if (baseName == null) block? Why not just exit the program
> gracefully instead of throwing the exception? If I pass it back up to the
Why, indeed?
> caller, what is is actually supposed to do, given that the message has
> been logged and recovery is not practical? Am I only passing it up so
> that getLocalizedText() can stop the program?
No, only the operator should stop the program.
The idea is to return to valid program state. RETURN TO VALID PROGRAM STATE.
*RETURN TO VALID PROGRAM STATE.*
>>> to that but I'm not sure what to do next. It seems pointless to carry
>>> on with getResources() since ResourceBundle.getBundle(baseName,
>>> locale) will fail on a NullPointerException with a null in either
>>> parameter. I could throw a NullPointerException so that
>>> getLocalizedText() can deal with it. But how do I get a stacktrace
>>> into the log if I follow that strategy? It's easy enough to get the
>>> stacktrace once I've caught an exception but I'm just talking about
>>> recognizing that an input parameter is null; there's no exception at
>>> that point to put in my log.
>>
>> There is if you create one. That's why Java has the 'new' operator.
>>
> Yes, I see that from your technique of creating one. I hadn't anticipated
> that approach.
That's why Java has the 'new' operator.
>>> If I let getResources() throw NullPointerException if either
>>> parameter is
>>
>> Better, use 'IllegalArgumentException'.
>>
>>> null, then I can let getLocalizedText() catch those
>>> NullPointerExceptions and get the stacktraces from the exception and
>>> write them to the log. In that case, I may as well just check the
>>> input parameters for nulls, and simply throw NullPointerException
>>> with a specific message within
>>
>> 'IllegalArgumentException'.
>>
> I have no strong feelings about this one way or the other but Bloch, on
> page 248 of Effective Java (2nd edition) says: "Arguably, all erroneous
> method invocations boil down to an illegal argument or an illegal state,
> but other exceptions are standardly used for certain kinds of illegal
> arguments and states. If a caller passes null in some parameter for which
> null values are prohibited, convention dictates that NullPointerException
> be thrown rather than IllegalArgumentException."
>
> Can we agree that whether I use IllegalArgumentException or
> NullPointerException in the situation I'm describing in my own code is
> simply a matter of personal style or preference? Or is there a reason to
> prefer IllegalArgumentException that Bloch failed to consider?
What do you think?
[snip]
>>> One other questions. When, if ever, should I execute System.exit()
>>> with a non-zero integer? In my example, I know that program Foo can't
>>> proceed
>>
>> Never. Program exit should be under user control.
>>
> So, given that my application has a GUI, leave the application suspended
> at the exception and make the user click the Close button? Why is that
> better than just exiting given that the program can't proceed without the
> missing resources in this case?
That depends. What constitutes valid program state? Should you just stop,
leaving the user wondering WTF happened? Should you perhaps come to a screen
that tells the user something went wrong, and give them some choices?
How do you feel when a program suddenly ends? What if you could've supplied
the missing "e" in the file name without having to start everything all over
again?
It all depends on the program, doesn't it?
Programs should really only end under operator control. But hey, do it your
way. What makes sense? What irritates the user? What's even possible?
> If this were a batch program rather than one with a GUI, would we close
> with System.exit()? Or wait for the operator to notice the program is
> suspended and make him kill it?
You tell me. The questions too vague. Describe the scenario precisely, with
the advantages and disadvantages of each approach. With more information about
your particular case, maybe I can advise.
--
Lew
Honi soit qui mal y pense.
http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
[toc] | [prev] | [next] | [standalone]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2012-03-11 17:00 -0300 |
| Message-ID | <Dv77r.36154$zD5.32316@newsfe12.iad> |
| In reply to | #12866 |
On 12-03-11 03:07 PM, Lew wrote: > Novice wrote: [ SNIP ] >> Assuming I'm not, I'm inclined to use the first approach you suggested. >> Or perhaps use the technique but throw a NullPointerException. Bloch >> implied that IllegalArgumentException was fine for bad values but that >> NullPointerException was preferred where a parameter had a null value. > > That's his opinion. > > Many others think that 'IllegalArgumentException' makes more sense if > it's an argument that has an illegal value. > > What do you think? [ SNIP ] StackOverflow has a good thread on this: http://stackoverflow.com/questions/3881/illegalargumentexception-or-nullpointerexception-for-a-null-parameter. Main takeaway is, in this case as in many others, as Lew suggests, you do better to understand *why* people are making certain suggestions, and then you can make your own choices. Most things in programming aren't black and white. Bear in mind, Bloch in "Effective Java" is trying to provide advice. He's pretty good at it, but he's not infallible. Sometimes it shades a bit too much over into "I say so...". I find it particularly rich that he tells us that NPE is to be preferred when a parameter is null and it's not allowed to be null, and the main reason is "convention dictates": seeing as how he wrote a lot of JDK classes he had a big hand in establishing the "convention", so this is quite circular. Don't get me wrong: ignore Bloch or Goetz or Lea and other people like that at your peril. But if you're experienced with technology X, and have in fact been using it as long and probably as thoroughly as some pundit, and you run across a statement by said pundit that you just can't see the sense of, don't assume the other guy is right. FWIW I use IllegalArgumentException in this case myself. I can't help NPEs that are thrown by JDK classes even when I think they made a mistake in choosing that exception, but for me an NPE means a dereferencing failure, and if I've got the choice to create or rethrow, I'll use IllegalArgumentException. AHS -- Last week I helped my friend stay put. It's a lot easier'n helpin' 'em move. I just went over to his house and made sure that he did not start to load shit into a truck. -- Mitch Hedberg
[toc] | [prev] | [next] | [standalone]
| From | Novice <novice@example..com> |
|---|---|
| Date | 2012-03-11 22:02 +0000 |
| Message-ID | <XnsA013B773176E8jpnasty@94.75.214.39> |
| In reply to | #12870 |
Arved Sandstrom <asandstrom3minus1@eastlink.ca> wrote in news:Dv77r.36154$zD5.32316@newsfe12.iad: > On 12-03-11 03:07 PM, Lew wrote: >> Novice wrote: > [ SNIP ] > >>> Assuming I'm not, I'm inclined to use the first approach you >>> suggested. Or perhaps use the technique but throw a >>> NullPointerException. Bloch implied that IllegalArgumentException >>> was fine for bad values but that NullPointerException was preferred >>> where a parameter had a null value. >> >> That's his opinion. >> >> Many others think that 'IllegalArgumentException' makes more sense if >> it's an argument that has an illegal value. >> >> What do you think? > [ SNIP ] > > StackOverflow has a good thread on this: > http://stackoverflow.com/questions/3881/illegalargumentexception-or-nul > lpointerexception-for-a-null-parameter. > > Main takeaway is, in this case as in many others, as Lew suggests, you > do better to understand *why* people are making certain suggestions, > and then you can make your own choices. Most things in programming > aren't black and white. > > Bear in mind, Bloch in "Effective Java" is trying to provide advice. > He's pretty good at it, but he's not infallible. Sometimes it shades a > bit too much over into "I say so...". I find it particularly rich that > he tells us that NPE is to be preferred when a parameter is null and > it's not allowed to be null, and the main reason is "convention > dictates": seeing as how he wrote a lot of JDK classes he had a big > hand in establishing the "convention", so this is quite circular. > Excellent, excellent point ;-) As someone who still feels like a novice about a lot of Java, I'm inclined to ascribe omniscience to the gurus and I need to stop doing that. They put their pants on one leg at a time just like I do and they are capable of being biased or even flat out wrong, although I'm sure I'm wrong a LOT more than they are ;-) > Don't get me wrong: ignore Bloch or Goetz or Lea and other people like > that at your peril. But if you're experienced with technology X, and > have in fact been using it as long and probably as thoroughly as some > pundit, and you run across a statement by said pundit that you just > can't see the sense of, don't assume the other guy is right. > Excellent advice. And of course you've just restated Lew's advice in your own words. > FWIW I use IllegalArgumentException in this case myself. I can't help > NPEs that are thrown by JDK classes even when I think they made a > mistake in choosing that exception, but for me an NPE means a > dereferencing failure, and if I've got the choice to create or > rethrow, I'll use IllegalArgumentException. > Like I said, I'm easy with either approach. Perhaps I'll use IllegalArgumentException on even-numbered days and NullPointerException on odd-numbered days just to show how even-handed I am ;-) -- Novice
[toc] | [prev] | [next] | [standalone]
| From | Arivald <NOSPAMarivald@interia.pl> |
|---|---|
| Date | 2012-03-11 21:03 +0100 |
| Message-ID | <jjj0i8$h2j$1@news.dialog.net.pl> |
| In reply to | #12866 |
W dniu 2012-03-11 19:07, Lew pisze:
> Novice wrote:
>> }
>>
>> //ResourceBundle resourceFile = null;
>>
>> try {
>> ResourceBundle resourceFile = ResourceBundle.getBundle(baseName,
>> locale);
>> return(resourceFile);
>> }
>> catch (MissingResourceException mrExcp) {
>> String msg = "Unable to find resources for base name, " + baseName + ",
>> and locale, " + locale + ". Check the spelling of the base name.";
>> throw new IllegalArgumentException(msg);
>> }
>> }
>> ========================================================================
>>
>> That works just fine and my exception, with stacktrace, is logged before
>> I've left getResources(). But why am I throwing the exception at the end
>> of the if (baseName == null) block? Why not just exit the program
>> gracefully instead of throwing the exception? If I pass it back up to the
>
> Why, indeed?
>
>> caller, what is is actually supposed to do, given that the message has
>> been logged and recovery is not practical? Am I only passing it up so
>> that getLocalizedText() can stop the program?
>
> No, only the operator should stop the program.
>
> The idea is to return to valid program state. RETURN TO VALID PROGRAM
> STATE.
>
> *RETURN TO VALID PROGRAM STATE.*
Some errors are so bad, so only program termination is applicable. For
example when there is no valid state to recover.
Novice resource bundles it may be this case. If he have all GUI in XML
in bundles, or at least all language dependant data (GUI labels, menus,
etc), there is no valid state to recover. In this case program should
notify user (message box, with only OK button), and just die.
For console program, there is much more reasons to use exit(). Most
console programs just exit on error. Very few, usually complex ones,
try to recover.
Yet another case is server-side applet. In this case exiting on error is
standard strategy. Although in this case it exits through unhandled
exception, so server can handle termination reason.
--
Arivald
[toc] | [prev] | [next] | [standalone]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2012-03-11 18:31 -0300 |
| Message-ID | <jR87r.32506$Ai4.6629@newsfe18.iad> |
| In reply to | #12871 |
On 12-03-11 05:03 PM, Arivald wrote: [ SNIP ] > For console program, there is much more reasons to use exit(). Most > console programs just exit on error. Very few, usually complex ones, try > to recover. [ SNIP ] I don't believe being a console program has anything to do with the error handling strategy. If the program can't continue in any useful form, except for making some last efforts at resource cleanup and some logging, that's when you exit automatically on error. Console program or otherwise. Otherwise you try to recover, or at least get to a state where the operator can make some necessary salvage decisions before being strongly advised to quit. But you don't automatically exit as a matter of course. "Console program" includes not just text-based UI but also CLI operation. This covers a lot of ground, up to and including servers. I've deployed and undeployed and bound apps on web and app servers, and configured the servers, entirely through CLI operations and editing configuration files, and no doubt so have you. That many of these apps also have web and desktop GUIs doesn't hide the fact that the core app is a console program. And you sure aren't going to exit on error with a server, not unless it's a really serious error. AHS -- Last week I helped my friend stay put. It's a lot easier'n helpin' 'em move. I just went over to his house and made sure that he did not start to load shit into a truck. -- Mitch Hedberg
[toc] | [prev] | [next] | [standalone]
| From | Novice <novice@example..com> |
|---|---|
| Date | 2012-03-11 21:54 +0000 |
| Message-ID | <XnsA013B63659242jpnasty@94.75.214.39> |
| In reply to | #12866 |
Lew <noone@lewscanon.com> wrote in news:jjipli$np7$1@news.albasani.net:
> Novice wrote:
>> Lew wrote:
>>> Novice wrote:
>>> snip
>>>> try {
>>>> locList = ResourceBundle.getBundle(baseName, locale);
>>>> }
>>>> catch (MissingResourceException mrExcp) {
>>>
>>> Log and return 'null' if that's the recovery strategy for this
>>> exception.
>>>
>> Is that what I should do, return null if there is a problem getting
>> the resource?
>>
>> I'm not sure if I should be returning anything at all. Maybe I should
>> just log and stop the program?
>
> I said *if* that's the strategy. What do you think? It may depend on
> the specifics of the case.
>
The bundle being sought is for use on the GUI. Displaying the GUI without
text is useless.
The nature of the error is a factor. If I'm passing a null for the
baseName, the program couldn't reasonably work out an alternate resource
bundle to use, nor could the user of the program. In that case, the
program should end with a SEVERE error written to the logs. If I'm
passing in a null locale, getResources() could determine the default
locale and use it, probably advising the user that it had done so and
logging that it had made this substitution. If the baseName were present
but misspelled, I don't see how the program could proceed.
So, in short, I could probably cope with a null locale but not a null or
misspelled baseName.
However, if the logic that I messed up in getLocalizedText() was supposed
to yield a language other than the one returned by Locale.getDefault()
(my proposed recovery strategy if locale is null in getResources(), the
GUI would display a different language than the user wanted. That might
be just as bad as a GUI without text if the user was, say, Japanese and
didn't know English, assuming English was the default locale.
>> Fair enough. I've converted each constants interface to a class with
>> a private constructor that throws an exception if someone tries to
>> instantiate it.
>
> How would that exception ever occur? How could "someone" ever try to
> call a private constructor?
>
> Don't throw code into a program that is provably never called.
>
>> Tip 6 in the article makes the point that it is redundant and
>> expensive
>
> We've discussed this before, remember?
>
> It's not expensive. When you're calling a logger statement for an
> error, the cost of the error SWAMPS the time in the logger. Think
> about it.
>
I suppose I'm too easily swayed by other opinions. Arved, who seems very
knowledgeable, cited that article, which seemed to give it his seal of
approval. I don't know the author of the article but I tend to assume he
must be an expert to be asked to write about a Java topic. The author
cites people who he considers experts and the upshot is that the advice
seems to argue against putting positioning information in the log unless
its necessary (which it probably isn't if the stacktrace is in the log).
Now you make a persuasive argument contradicting the article. I'm
satisfied that you have serious expertise in this area so I have no
reason to dismiss your argument. But why didn't the experts who wrote the
article modify their remarks accordingly?
I am more than happy to include class name, method name and line number
in a log record. Those three things and the message text are the most
useful parts of the log record to me. They give me enough information
that I can find the right spot in the code and start to set up test
conditions to try to duplicate the error and find out what is causing it.
The stacktrace gives me that key information too but one of the questions
I haven't asked yet is whether I should always put a stacktrace in the
log for every problem situation. I'm inclined to think I should do so for
errors that get logged as SEVERE but not for FINE/FINER/FINEST messages.
WARNING and INFO messages are iffier and probably have to be decided on a
case-by-case basis. If I'm not writing a stacktrace, then I'll want the
log record to include the message, class name, method name and line
number at the very least and very likely things like the thread if I'm
doing multiple threads.
>> to get class, method and line information if it is already in the log
>> message. A stacktrace will tell me all of that and more so shouldn't
>> I be concentrating on getting a stacktrace, plus whatever I'll need
>> that isn't in the stacktrace, like the date and time of the problem?
>
> There are many who have answered this question, in response to your
> questions.
>
> The answers covered a lot of approaches. Perhaps you recall them.
>
I've had a lot of suggestions over the last few days and, in all honesty,
they are starting to blur in my mind.... Obviously, I need to reread some
of those threads....
>>>> Now, finally, here are some questions:
>>>>
>>>> Since the only exceptions I anticipate, MissingResourceException
>>>> and NullPointerException, are unchecked exceptions, I gather than I
>>>> shouldn't really do anything about them aside from logging when
>>>> they happen. Okay,
>>>
>>> I disagree. You should end the program gracefully and get someone to
>>> fix the programming error right away.
>>>
>> But what's the right way to end the program? System.exit()? That
>> seems
>
> Under operator control.
>
>> the obvious way but as I've said further down, that doesn't seem to
>> be the method used in the books and articles I've been reading.
>> What's the better way?
>
> Under operator control.
>
>>>> fair enough; I certainly don't want to display the source code to
>>>> my user, make them enter the correct value for the baseName, make
>>>> them recompile the program and then run it again! But when/where
>>>> should I log the error? For instance, if I mess up my coding
>>>> somehow and inadvertently
>>>
>>> In the log file.
>>>
>> Yes, I realize that it goes in the log file. I mean when and where in
>> my code do I do that? In getResource() or getLocalizedText()?
>
> Wherever you detect the error.
>
Good. That makes perfect sense to me.
>>>> pass a null in the baseName, should getResources() be testing its
>>>> input parameters individually to see if they are null and write a
>>>> message to the log if they are null from within that method? I'm
>>>> inclined to say yes
>>>
>>> Always check all parameters for validity, either by an explicit
>>> check for a public or protected method, or by controlling what's
>>> passed to package-private or private methods.
>>>
>>> A normal practice is to have an application-specific checked
>>> exception to throw, or to throw the standard unchecked exception.
>>> For example:
>>>
>>> if (argument == null)
>>> {
>>> final String msg = "null argument";
>>> IllegalArgumentException except = new
>>> IllegalArgumentException(msg); logger.error(msg, except);
>>> throw except;
>>> }
>>>
>>> or similarly for application checked exception 'FooException'.
>>>
>>> throw new FooException(new IllegalArgumentException(msg));
>>>
>> At least one of the articles/books recommended against creating
>> custom exceptions unless necessary, preferring to use existing
>> exceptions where possible.
>>
>> The Java Tutorial puts it this way:
>>
>> "You should write your own exception classes if you answer yes to any
>> of the following questions; otherwise, you can probably use someone
>> else's.
>>
>> - Do you need an exception type that isn't represented by those in
>> the Java platform?
>> - Would it help users if they could differentiate your exceptions
>> from those thrown by classes written by other vendors?
>> - Does your code throw more than one related exception?
>> - If you use someone else's exceptions, will users have access to
>> those exceptions? A similar question is, should your package be
>> independent and self-contained?"
>>
>> I don't _think_ I qualify to create my own exception under any of
>> these conditions so I'm inclined to stay with the standard ones. Or
>> am I missing something?
>
> Yes.
>
> It is common and frequently useful to create an application-specific
> checked exception. Again, and I've said this many times, think about
> what will be useful when troubleshooting a problem. Many times, a
> custom exception is useful. It says that the underlying exception has
> been caught, logged and wrapped.
>
But how is a custom FooException better than a good ol'
IllegalArgumentException? I'm not quite getting that yet.
Please understand that I have no objection to creating my own exceptions.
I've actually done it in the past and didn't find it difficult.
> Runtime exceptions are dangerous because they slip past you. If you
> catch them in a custom checked exception then code must handle it. All
> those runtime exceptions are related, by dint of being exceptions
> within the same application. BOOM! Qualified.
>
It sounds a little bit like you're saying that RuntimeExceptions should
be made into chccked exceptions when possible. But I doubt you mean that.
That seems to contradict what Stelting at least is saying and even the
API. The spirit of the API seems to be that some things don't lend
themselves to easy recovery and you shouldn't even try, ergo the
existence of unchecked exceptions and errors. Naturally, some things DO
lend themselves to easy recovery by the user so it makes perfect sense
that if a given file isn't found, the user can be given a chance to
select a different file with a file chooser, which explains why
FileNotFoundException is a checked exception.
>> Assuming I'm not, I'm inclined to use the first approach you
>> suggested. Or perhaps use the technique but throw a
>> NullPointerException. Bloch implied that IllegalArgumentException was
>> fine for bad values but that NullPointerException was preferred where
>> a parameter had a null value.
>
> That's his opinion.
>
> Many others think that 'IllegalArgumentException' makes more sense if
> it's an argument that has an illegal value.
>
> What do you think?
>
Like I said, I'm fine with either approach. They're both unchecked
exceptions and you'd handle them the same way. It feels like a matter of
personal style to me, meaning I'm free to do what I like on my own code
and I should follow the shop standard if I'm working for someone else.
>>> Somewhere up the stack you should catch the exception and convert it
>>> to valid program state"
>>>
>>> catch(RuntimeException except)
>>> {
>>> forwardProgramControlToErrorScreen();
>>> }
>>>
>> I went into Eclipse for a minute and amended getResources() to look
>> like this:
>>
>> ======================================================================
>> == static public ResourceBundle getResources(String baseName, Locale
>> locale) throws NullPointerException, IllegalArgumentException {
>>
>> if (baseName == null) {
>> final String msg = "The base name cannot be null.";
>> NullPointerException nullPointerException = new
>> NullPointerException
>> (msg);
>> Logger logger = Logger.getLogger(CLASS_NAME);
>> logger.log(Level.SEVERE, msg, nullPointerException);
>> throw nullPointerException;
>> }
>>
>> if (locale == null) {
>> final String msg = "The locale cannot be null."; //$NON-NLS-1$
>> NullPointerException nullPointerException = new
>> NullPointerException
>> (msg);
>> Logger logger = Logger.getLogger(CLASS_NAME);
>> logger.log(Level.SEVERE, msg, nullPointerException);
>> throw nullPointerException;
>
> Kind of a bad name for the variable, there.
>
You mean nullPointerException? I've gotten into the habit of giving my
instance names the same name as the class (except for the case of the
first letter) so I'm used to doing things that way. It seems clearer
since it avoids any possibly misunderstanding that this isn't just an
exception but is an instance of NullPointerException.
> What does your log look like with 'msg' printed twice?
>
A bit redundant given that the same message appears at the top of the
stacktrace. But just having "SEVERE" without any other message seems like
a bad idea. What do you think I should have if in the log record (the
part that isn't the stacktrace) if not 'msg'?
>> }
>>
>> //ResourceBundle resourceFile = null;
>>
>> try {
>> ResourceBundle resourceFile = ResourceBundle.getBundle(baseName,
>> locale);
>> return(resourceFile);
>> }
>> catch (MissingResourceException mrExcp) {
>> String msg = "Unable to find resources for base name, " + baseName
>> + ",
>> and locale, " + locale + ". Check the spelling of the base name.";
>> throw new IllegalArgumentException(msg);
>> }
>> }
>> ======================================================================
>> ==
>>
>> That works just fine and my exception, with stacktrace, is logged
>> before I've left getResources(). But why am I throwing the exception
>> at the end of the if (baseName == null) block? Why not just exit the
>> program gracefully instead of throwing the exception? If I pass it
>> back up to the
>
> Why, indeed?
>
>> caller, what is is actually supposed to do, given that the message
>> has been logged and recovery is not practical? Am I only passing it
>> up so that getLocalizedText() can stop the program?
>
> No, only the operator should stop the program.
>
I think I need to be clear about who the operator is. In the case of a
game, say, we're talking about the person playing the game (assuming a
game that has only one player, like a solitaire game). Same kind of
reasoning for a utility like a program that burns CDs or whatnot. For a
servlet that is running in a container like Tomcat and may have hundreds
or thousands of instances running, we'd have both individual users of
individual copies of the program as well as some kind of admininstrator
managing the container. Have I got that about right?
If so, I'm not clear which operator you mean in the case of a servelet.
Assuming only one instance of an application was having trouble, I'd
expect the user to be the operator in question. In a case where all
instances of an application were having problems, I'd expect the
administrator of the container to shut down all instance of the problem
program pending a resolution.
If that's all more-or-less right so far, then what is the operator
experience going to be when the program has to deal with a null baseName
and the program is a game or utility? It would seem reasonable to display
a dialog with a "Sorry, we hit a snag and can't proceed" kind of message
that includes an okay button. It could go further and advise the user to
contact Tech Support and even display messages and diagnostics but I
expect most of that would be over the heads of users and should be
reserved for the logs. Then, when they press Okay, the program ends.
Is that about what you had in mind?
> The idea is to return to valid program state. RETURN TO VALID PROGRAM
> STATE.
>
> *RETURN TO VALID PROGRAM STATE.*
>
I hear you; I'm just not sure what a valid program state would be in my
case. Honestly, I'm not entirely sure what "valid program state" implies
in ANY case ;-)
>>>> to that but I'm not sure what to do next. It seems pointless to
>>>> carry on with getResources() since
>>>> ResourceBundle.getBundle(baseName, locale) will fail on a
>>>> NullPointerException with a null in either parameter. I could throw
>>>> a NullPointerException so that getLocalizedText() can deal with it.
>>>> But how do I get a stacktrace into the log if I follow that
>>>> strategy? It's easy enough to get the stacktrace once I've caught
>>>> an exception but I'm just talking about recognizing that an input
>>>> parameter is null; there's no exception at that point to put in my
>>>> log.
>>>
>>> There is if you create one. That's why Java has the 'new' operator.
>>>
>> Yes, I see that from your technique of creating one. I hadn't
>> anticipated that approach.
>
> That's why Java has the 'new' operator.
>
>>>> If I let getResources() throw NullPointerException if either
>>>> parameter is
>>>
>>> Better, use 'IllegalArgumentException'.
>>>
>>>> null, then I can let getLocalizedText() catch those
>>>> NullPointerExceptions and get the stacktraces from the exception
>>>> and write them to the log. In that case, I may as well just check
>>>> the input parameters for nulls, and simply throw
>>>> NullPointerException with a specific message within
>>>
>>> 'IllegalArgumentException'.
>>>
>> I have no strong feelings about this one way or the other but Bloch,
>> on page 248 of Effective Java (2nd edition) says: "Arguably, all
>> erroneous method invocations boil down to an illegal argument or an
>> illegal state, but other exceptions are standardly used for certain
>> kinds of illegal arguments and states. If a caller passes null in
>> some parameter for which null values are prohibited, convention
>> dictates that NullPointerException be thrown rather than
>> IllegalArgumentException."
>>
>> Can we agree that whether I use IllegalArgumentException or
>> NullPointerException in the situation I'm describing in my own code
>> is simply a matter of personal style or preference? Or is there a
>> reason to prefer IllegalArgumentException that Bloch failed to
>> consider?
>
> What do you think?
>
I'm easy with either approach. It feels like a personal style thing to
me. The main thing is that the problem is detected and logged with enough
information that the operators and/or programmers can figure out what
went wrong. At the end of the day, the specific exception thrown doesn't
seem particularly important.
> [snip]
>>>> One other questions. When, if ever, should I execute System.exit()
>>>> with a non-zero integer? In my example, I know that program Foo
>>>> can't proceed
>>>
>>> Never. Program exit should be under user control.
>>>
>> So, given that my application has a GUI, leave the application
>> suspended at the exception and make the user click the Close button?
>> Why is that better than just exiting given that the program can't
>> proceed without the missing resources in this case?
>
> That depends. What constitutes valid program state? Should you just
> stop, leaving the user wondering WTF happened? Should you perhaps come
> to a screen that tells the user something went wrong, and give them
> some choices?
>
Aside from not being clear about the meaning of "program state", I see
your point.
> How do you feel when a program suddenly ends? What if you could've
> supplied the missing "e" in the file name without having to start
> everything all over again?
>
Absolutely. I think it would be dandy to enlist the user's assistance in
getting back out of trouble rather than crash the program on him.
> It all depends on the program, doesn't it?
>
Yes.
> Programs should really only end under operator control. But hey, do it
> your way. What makes sense? What irritates the user? What's even
> possible?
>
Fair enough. I'm all in favor of the user having a positive experience
rather than have them scratching their heads and muttering WTF!
In short, you've won me over. I think displaying a dialog and explaining
that we have to end is more than reasonable and is better than just
closing it on the user's behalf without any clear communication. My only
quibble is that the dialog is a bit of an empty gesture in the sense that
the user doesn't REALLY have much in the way of control when he gets a
dialog with only an Okay button on it. The program is already dead in the
water and his only option is to press Okay to officially kill the
program. That's not really "control" in a very strong sense. But I agree
that it is strongly preferable to do that than to just close it without
telling him what's going on in some way.
>> If this were a batch program rather than one with a GUI, would we
>> close with System.exit()? Or wait for the operator to notice the
>> program is suspended and make him kill it?
>
> You tell me. The questions too vague. Describe the scenario precisely,
> with the advantages and disadvantages of each approach. With more
> information about your particular case, maybe I can advise.
>
I didn't really have a specific scenario in mind when I said that. It
just struck me that the answer would probably be different in a situation
like that than the case of a standalone utility or game. As you say, a
good programmer would consider that in devising his strategy for handling
the problem.
--
Novice
[toc] | [prev] | [next] | [standalone]
| From | Patricia Shanahan <pats@acm.org> |
|---|---|
| Date | 2012-03-11 15:26 -0700 |
| Message-ID | <S7GdnRomTdoRu8DSnZ2dnUVZ_sWdnZ2d@earthlink.com> |
| In reply to | #12878 |
On 3/11/2012 2:54 PM, Novice wrote: > Lew<noone@lewscanon.com> wrote in news:jjipli$np7$1@news.albasani.net: ... >> It is common and frequently useful to create an application-specific >> checked exception. Again, and I've said this many times, think about >> what will be useful when troubleshooting a problem. Many times, a >> custom exception is useful. It says that the underlying exception has >> been caught, logged and wrapped. >> > But how is a custom FooException better than a good ol' > IllegalArgumentException? I'm not quite getting that yet. Generally, you should use different Exception subclasses for cases that may need different handling, so that callers can set up appropriate catch blocks. Regardless of the conditions under which you choose to generate IllegalArgumentException, many methods you will be calling use it to indicate an illegal argument condition that has not yet been logged or otherwise reported. If you also use it to indicate exceptions that have already been logged, you risk either repeated logging of the same issue, or failure to log. On the other hand, if you create an Exception subclass that you only throw after logging the underlying problem, there is no ambiguity. Callers have to deal with the consequences of the failure, but should only generate log messages if they have something to add. The underlying problem has already been logged. Patricia
[toc] | [prev] | [next] | [standalone]
| From | Novice <novice@example..com> |
|---|---|
| Date | 2012-03-11 23:23 +0000 |
| Message-ID | <XnsA013C5393E0CEjpnasty@94.75.214.39> |
| In reply to | #12883 |
Patricia Shanahan <pats@acm.org> wrote in news:S7GdnRomTdoRu8DSnZ2dnUVZ_sWdnZ2d@earthlink.com: > On 3/11/2012 2:54 PM, Novice wrote: >> Lew<noone@lewscanon.com> wrote in news:jjipli$np7$1 @news.albasani.net: > ... >>> It is common and frequently useful to create an application-specific >>> checked exception. Again, and I've said this many times, think about >>> what will be useful when troubleshooting a problem. Many times, a >>> custom exception is useful. It says that the underlying exception has >>> been caught, logged and wrapped. >>> >> But how is a custom FooException better than a good ol' >> IllegalArgumentException? I'm not quite getting that yet. > > Generally, you should use different Exception subclasses for cases that > may need different handling, so that callers can set up appropriate > catch blocks. > > Regardless of the conditions under which you choose to generate > IllegalArgumentException, many methods you will be calling use it to > indicate an illegal argument condition that has not yet been logged or > otherwise reported. > > If you also use it to indicate exceptions that have already been logged, > you risk either repeated logging of the same issue, or failure to log. > > On the other hand, if you create an Exception subclass that you only > throw after logging the underlying problem, there is no ambiguity. > Callers have to deal with the consequences of the failure, but should > only generate log messages if they have something to add. The underlying > problem has already been logged. > I'm sure this will seem like good advice when I understand it but it's still vague to me. It would really help if you could suggest a concrete example or two that show when to use a custom exception and why it's better. -- Novice
[toc] | [prev] | [next] | [standalone]
| From | Lew <noone@lewscanon.com> |
|---|---|
| Date | 2012-03-11 16:52 -0700 |
| Message-ID | <jjjdsa$984$1@news.albasani.net> |
| In reply to | #12888 |
Novice wrote: > Patricia Shanahan : >> Novice wrote: >>> Lew wrote: >> ... >>>> It is common and frequently useful to create an application-specific >>>> checked exception. Again, and I've said this many times, think about >>>> what will be useful when troubleshooting a problem. Many times, a >>>> custom exception is useful. It says that the underlying exception has >>>> been caught, logged and wrapped. >>>> >>> But how is a custom FooException better than a good ol' >>> IllegalArgumentException? I'm not quite getting that yet. >> >> Generally, you should use different Exception subclasses for cases that >> may need different handling, so that callers can set up appropriate >> catch blocks. >> >> Regardless of the conditions under which you choose to generate >> IllegalArgumentException, many methods you will be calling use it to >> indicate an illegal argument condition that has not yet been logged or >> otherwise reported. >> >> If you also use it to indicate exceptions that have already been > logged, >> you risk either repeated logging of the same issue, or failure to log. >> >> On the other hand, if you create an Exception subclass that you only >> throw after logging the underlying problem, there is no ambiguity. >> Callers have to deal with the consequences of the failure, but should >> only generate log messages if they have something to add. The > underlying >> problem has already been logged. >> > I'm sure this will seem like good advice when I understand it but it's > still vague to me. > > It would really help if you could suggest a concrete example or two that > show when to use a custom exception and why it's better. This is treading into the matter of art. I can show the idiom, but no way can I generate an entire project for you to show the impact of the logging strategy across the project, which is the point of the idiom. Your entire application has layers. The deeper low-level layers are most likely to encounter problems first. Runtime exceptions are indicative of programming errors, but they're slippery, too. You don't have to catch them, which means an unguarded runtime exception can bring your system crashing down. That's not something you want to design it to do. A low-level layer by definition brings some model of the world into conformance with your application's model. It might read a file and extract data to objects, or persist objects to a database, or transform your application's model into and out of XML documents for communication to other modules. Whatever the low layer does, the higher-level client code deals with abstractions relevant to the program. It's no longer a database record, for example, it's a 'Customer' with related 'Order' elements in a collection. If something goes wrong at a deep layer, the higher-level client must first, become aware of it, and second, have some way to handle it. At that level, "runtime exception" or 'IOException' are too low-level - they aren't in the semantics of the application model. So the lower level, in addition to transforming extrinsic models of good stuff into the application domain, also must transform bad stuff like exceptions. One good way to do this is to have an application-specific checked exception like 'FooException' for the "Foo" application. As Patricia says, this marks for higher-level code that lower-level stuff has done its job. At the higher level, we care only that the details are packaged in the exception's 'cause', not what the details are. A 'FooException', being checked, must be caught, so it cannot accidentally crash the application. Since all higher-level code sees 'FooException' as a marker for bad stuff, and a black box, they all do the same thing with it, more or less. They return the program to valid state "state" - definable by a quick Google search, for Pete's sake! Come on, man! Do a /little/ of the lifting yourself. And no, this isn't "bludgeoning". You get your ego in the way and you won't learn. There's a reason we expect you to act like a professional. such as a decision screen or restart position, perhaps extracting standardized fields from the 'FooException' for the error message. Much of programming only makes sense if you think architecturally - that is, holistically. Each layer has its own job, and its own vocabulary for that job. "Foo" has no business knowing about "I/O" in its Foo-specific logic, and no business knowing about "Foo" behavior in its I/O logic. Separation of concerns. Law of Demeter. Object oriented. Modularity. -- Lew Honi soit qui mal y pense. http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
[toc] | [prev] | [next] | [standalone]
| From | Novice <novice@example..com> |
|---|---|
| Date | 2012-03-12 17:16 +0000 |
| Message-ID | <XnsA01486FC2B5E8jpnasty@94.75.214.39> |
| In reply to | #12891 |
Lew <noone@lewscanon.com> wrote in news:jjjdsa$984$1@news.albasani.net:
> Novice wrote:
>> Patricia Shanahan :
>>> Novice wrote:
>>>> Lew wrote:
>>> ...
>>>>> It is common and frequently useful to create an
>>>>> application-specific checked exception. Again, and I've said this
>>>>> many times, think about what will be useful when troubleshooting a
>>>>> problem. Many times, a custom exception is useful. It says that
>>>>> the underlying exception has been caught, logged and wrapped.
>>>>>
>>>> But how is a custom FooException better than a good ol'
>>>> IllegalArgumentException? I'm not quite getting that yet.
>>>
>>> Generally, you should use different Exception subclasses for cases
>>> that may need different handling, so that callers can set up
>>> appropriate catch blocks.
>>>
>>> Regardless of the conditions under which you choose to generate
>>> IllegalArgumentException, many methods you will be calling use it to
>>> indicate an illegal argument condition that has not yet been logged
>>> or otherwise reported.
>>>
>>> If you also use it to indicate exceptions that have already been
>> logged,
>>> you risk either repeated logging of the same issue, or failure to
>>> log.
>>>
>>> On the other hand, if you create an Exception subclass that you only
>>> throw after logging the underlying problem, there is no ambiguity.
>>> Callers have to deal with the consequences of the failure, but
>>> should only generate log messages if they have something to add. The
>> underlying
>>> problem has already been logged.
>>>
>> I'm sure this will seem like good advice when I understand it but
>> it's still vague to me.
>>
>> It would really help if you could suggest a concrete example or two
>> that show when to use a custom exception and why it's better.
>
> This is treading into the matter of art. I can show the idiom, but no
> way can I generate an entire project for you to show the impact of the
> logging strategy across the project, which is the point of the idiom.
>
> Your entire application has layers. The deeper low-level layers are
> most likely to encounter problems first. Runtime exceptions are
> indicative of programming errors, but they're slippery, too. You don't
> have to catch them, which means an unguarded runtime exception can
> bring your system crashing down. That's not something you want to
> design it to do.
>
> A low-level layer by definition brings some model of the world into
> conformance with your application's model. It might read a file and
> extract data to objects, or persist objects to a database, or
> transform your application's model into and out of XML documents for
> communication to other modules. Whatever the low layer does, the
> higher-level client code deals with abstractions relevant to the
> program. It's no longer a database record, for example, it's a
> 'Customer' with related 'Order' elements in a collection.
>
> If something goes wrong at a deep layer, the higher-level client must
> first, become aware of it, and second, have some way to handle it. At
> that level, "runtime exception" or 'IOException' are too low-level -
> they aren't in the semantics of the application model. So the lower
> level, in addition to transforming extrinsic models of good stuff into
> the application domain, also must transform bad stuff like exceptions.
>
> One good way to do this is to have an application-specific checked
> exception like 'FooException' for the "Foo" application. As Patricia
> says, this marks for higher-level code that lower-level stuff has done
> its job. At the higher level, we care only that the details are
> packaged in the exception's 'cause', not what the details are. A
> 'FooException', being checked, must be caught, so it cannot
> accidentally crash the application. Since all higher-level code sees
> 'FooException' as a marker for bad stuff, and a black box, they all do
> the same thing with it, more or less. They return the program to valid
> state
>
> "state" - definable by a quick Google search, for Pete's sake! Come
> on, man! Do a /little/ of the lifting yourself. And no, this isn't
> "bludgeoning". You get your ego in the way and you won't learn.
> There's a reason we expect you to act like a professional.
>
> such as a decision screen or restart position, perhaps extracting
> standardized fields from the 'FooException' for the error message.
>
> Much of programming only makes sense if you think architecturally -
> that is, holistically. Each layer has its own job, and its own
> vocabulary for that job. "Foo" has no business knowing about "I/O" in
> its Foo-specific logic, and no business knowing about "Foo" behavior
> in its I/O logic.
>
> Separation of concerns.
> Law of Demeter.
> Object oriented.
> Modularity.
>
I can see why it's hard to be specific about this issue without actually
building a whole, complex project. I don't want to ask too much of anyone
on this newsgroup and building a complex project is surely excessive.
It's just that I really need to hear both principles AND concrete
examples to be sure I really understand the principles. But let's try to
keep this at the principle level for the most part.
I see your point about how the low levels of a program are very narrowly
focused on doing something like finding a resource and don't know - and
shouldn't care - about the significance of that low level task. Those low
level methods don't know what the resource bundle is for or what the
consequences are if the bundle can't be found. It makes sense that the
decision about what to do if that search fails should be higher up in the
logic. The higher level will know if that is a show-stopper or is
recoverable. Some programs may have practical recovery options if the
bundle is missing while others may not.
I suppose it also makes sense that the higher level logic wants to think
in terms of "Foo problems" rather than IllegalArgumentExceptions. The
person writing Foo just wants to know if the problem in the lower level
method is a show-stopper or is recoverable and probably doesn't care if
it is a checked or unchecked exception or an error.
But I'm not quite seeing all the implications yet.
Are you envisioning that our hypothetical Foo would have a single
FooException that it wraps around everything that percolates up from the
lower levels? Or would there be a bunch of FooExceptions, each handling
different sorts of problems?
And what happens with logging? Do we just log the error as an
IllegalArgumentException (or whatever) when we find it at the low level?
Or do we also log it again, this time as a FooException, when we deal
with it at the higher levels? I'm uneasy about writing what are
effectively redundant messages to the log.
For what it's worth, I've cobbled together a CrashDialog class which my
higher level methods, getLocalizedText() for example, displays when it
handles an IllegalArgumentException() if it is thrown by getResources().
(I'm now throwing IllegalArgumentException for nulls in the parameters as
well as a failed getBundle()). In that case, the CrashDialog class says:
===================================================================
Foo - Severe Error
The program has to stop for the following reason: Certain language
resources were not available.
The problem has been logged and Technical Support will begin resolving
the error shortly.
[Okay]
====================================================================
The line about Technical Support resolving the problem shortly is
somewhat fanciful since I'm the whole development team and the entire
universe of end users at the moment ;-) I'm just envisioning what I'd say
in a real production application.
The bit about the language resources being unavailable is not completely
satisfactory because it is probably not very helpful to a non-technical
user but it seemed better to summarize the situation than to use the
message from the exception; the user is even less likely to comprehend
"the baseName must not be null" or "Unable to find resources for base
name, com.novice.foo.FooTextzzz, and locale, jp_JP. Check the spelling of
the base name". And I certainly don't want to display a stacktrace to the
user!
I've also logged the fact that the user clicked on okay to end the
program as another SEVERE error. Mind you, that seems redundant and I'm
inclined to remove that code again. I'm assuming that in the real world,
one SEVERE error is going to be enough to get the attention of the
appropriate people and producing two or three SEVERE errors about the
same problem is not going to get the problem examined any sooner. Correct
me if I'm wrong!
Now, that behavior wouldn't be standard for all cases. If the error is
recoverable, the user would get different instructions that would lead
him/her through whatever needs to be done to recover. And some errors
might not be severe at all and just be informational. In those cases, the
dialog might say "Information" instead of Severe Error and simply
describe whatever workaround Foo adopted to get past the problem.
I'm feeling good about the error handling and logging now. It's starting
to fall into place for me, aside from the whole custom exception
question.
--
Novice
[toc] | [prev] | [next] | [standalone]
| From | Lew <noone@lewscanon.com> |
|---|---|
| Date | 2012-03-13 08:31 -0700 |
| Message-ID | <jjnp94$5qe$1@news.albasani.net> |
| In reply to | #12901 |
Novice wrote: > Are you envisioning that our hypothetical Foo would have a single > FooException that it wraps around everything that percolates up from the > lower levels? Or would there be a bunch of FooExceptions, each handling > different sorts of problems? Quite often a single exception type suffices. You would only add another if there were a crying need for it. > And what happens with logging? Do we just log the error as an > IllegalArgumentException (or whatever) when we find it at the low level? Did you read Patricia's advice on this very matter? > Or do we also log it again, this time as a FooException, when we deal > with it at the higher levels? I'm uneasy about writing what are > effectively redundant messages to the log. Patricia recommended, and I agree, that the custom exception serve as a signal that the lower-level problem has been logged. Remember? > For what it's worth, I've cobbled together a CrashDialog class which my > higher level methods, getLocalizedText() for example, displays when it > handles an IllegalArgumentException() if it is thrown by getResources(). > (I'm now throwing IllegalArgumentException for nulls in the parameters as > well as a failed getBundle()). In that case, the CrashDialog class says: Is a failed 'getBundle()' really a programming error? Is it really an illegal argument? There was nothing illegal about the argument /per se/ if the resource just happened not to be available. I suggest a checked exception, either 'IOException' or a subtype thereof, for a missing bundle, unless it really and truly is completely under programmer control. (And deployment-time issues never are.) > =================================================================== > Foo - Severe Error > > The program has to stop for the following reason: Certain language > resources were not available. > > The problem has been logged and Technical Support will begin resolving > the error shortly. > > [Okay] > ==================================================================== > > The line about Technical Support resolving the problem shortly is > somewhat fanciful since I'm the whole development team and the entire > universe of end users at the moment ;-) I'm just envisioning what I'd say > in a real production application. Be careful of making promises because you must keep them. Well, technically you don't have to, but do you want to be that guy? > The bit about the language resources being unavailable is not completely > satisfactory because it is probably not very helpful to a non-technical > user but it seemed better to summarize the situation than to use the > message from the exception; the user is even less likely to comprehend > "the baseName must not be null" or "Unable to find resources for base > name, com.novice.foo.FooTextzzz, and locale, jp_JP. Check the spelling of > the base name". And I certainly don't want to display a stacktrace to the > user! > > I've also logged the fact that the user clicked on okay to end the > program as another SEVERE error. Mind you, that seems redundant and I'm How is that any kind of error? > inclined to remove that code again. I'm assuming that in the real world, > one SEVERE error is going to be enough to get the attention of the > appropriate people and producing two or three SEVERE errors about the > same problem is not going to get the problem examined any sooner. Correct > me if I'm wrong! Don't worry, we will. But you have a brain. What makes sense there? What would look funny to the ops guy? Are you really thinking like a troubleshooter in the field, or like the programmer whose name that troubleshooter will curse? > Now, that behavior wouldn't be standard for all cases. If the error is > recoverable, the user would get different instructions that would lead > him/her through whatever needs to be done to recover. And some errors > might not be severe at all and just be informational. In those cases, the > dialog might say "Information" instead of Severe Error and simply > describe whatever workaround Foo adopted to get past the problem. > > I'm feeling good about the error handling and logging now. It's starting > to fall into place for me, aside from the whole custom exception > question. What do you mean by "recoverable"? I mean able to show an error dialog and invite the operator to shut down. Is that not a valid program state? -- Lew Honi soit qui mal y pense. http://upload.wikimedia.org/wikipedia/commons/c/cf/Friz.jpg
[toc] | [prev] | [next] | [standalone]
| From | Patricia Shanahan <pats@acm.org> |
|---|---|
| Date | 2012-03-11 17:51 -0700 |
| Message-ID | <QdidndGYsfwc1cDSnZ2dnUVZ_tKdnZ2d@earthlink.com> |
| In reply to | #12888 |
On 3/11/2012 4:23 PM, Novice wrote: > Patricia Shanahan<pats@acm.org> wrote in > news:S7GdnRomTdoRu8DSnZ2dnUVZ_sWdnZ2d@earthlink.com: > >> On 3/11/2012 2:54 PM, Novice wrote: >>> Lew<noone@lewscanon.com> wrote in news:jjipli$np7$1 > @news.albasani.net: >> ... >>>> It is common and frequently useful to create an application-specific >>>> checked exception. Again, and I've said this many times, think about >>>> what will be useful when troubleshooting a problem. Many times, a >>>> custom exception is useful. It says that the underlying exception has >>>> been caught, logged and wrapped. >>>> >>> But how is a custom FooException better than a good ol' >>> IllegalArgumentException? I'm not quite getting that yet. >> >> Generally, you should use different Exception subclasses for cases that >> may need different handling, so that callers can set up appropriate >> catch blocks. >> >> Regardless of the conditions under which you choose to generate >> IllegalArgumentException, many methods you will be calling use it to >> indicate an illegal argument condition that has not yet been logged or >> otherwise reported. >> >> If you also use it to indicate exceptions that have already been > logged, >> you risk either repeated logging of the same issue, or failure to log. >> >> On the other hand, if you create an Exception subclass that you only >> throw after logging the underlying problem, there is no ambiguity. >> Callers have to deal with the consequences of the failure, but should >> only generate log messages if they have something to add. The > underlying >> problem has already been logged. >> > I'm sure this will seem like good advice when I understand it but it's > still vague to me. > > It would really help if you could suggest a concrete example or two that > show when to use a custom exception and why it's better. > Using the same exception for "illegal argument" and "already logged and wrapped" is unlikely to get you into much trouble in a short program viewed for a few minutes. The potential trouble comes when you have a large program, too large to read the whole thing before making a change, and it is being modified by a programmer who does not know, or does not remember, that the exception has those two meanings. That makes it difficult to illustrate in a small example. Remember that a lot of what you are being told, both in the newsgroup and in the articles you are reading, is based on experience with maintaining large programs over many years. Patricia
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.java.programmer
csiph-web