Path: csiph.com!usenet.pasdenom.info!news.albasani.net!.POSTED!not-for-mail From: Lew Newsgroups: comp.lang.java.programmer Subject: Re: Exception Handling Date: Sat, 10 Mar 2012 18:39:48 -0800 Organization: albasani.net Lines: 186 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Trace: news.albasani.net 77CfaKO/mvdnO2bUPfr1j6hQ4/O2xrfVqj+wkVk/NsPH0UXb9zOhFXxf70YMRY2dymkvo49L3zNye3dRi2fv9HpTJA4LCDywGrz+A4ZYjPmyWNvuTQo4sBFsrjdMFba+ NNTP-Posting-Date: Sun, 11 Mar 2012 02:39:43 +0000 (UTC) Injection-Info: news.albasani.net; logging-data="27KFYZ0aH0/cWf+6aY/OK1z++NKGCg3yCSkSs5vDUEujB4oKhVU2DIhzhYiCJEEtC9E/pDS8FdYldgN41t5g2TZYd8JsGyU/3dNpt37kK3vGNV1OtdRjfCnvltP7EGnT"; mail-complaints-to="abuse@albasani.net" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.2) Gecko/20120216 Thunderbird/10.0.2 In-Reply-To: Cancel-Lock: sha1:gF1fyYBvcvyVNM2JmJmAe40h0Gc= Xref: csiph.com comp.lang.java.programmer:12859 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