How to deal with unprecised exceptions
John Zukowski
(Jaz@zukowski.net) President, JZ Ventures, Inc. August 2004
Tracking unforeseen runtime exceptions may be a slow and laborious thing, only getting default thread names and stack tracking usually not enough. In taming Tiger, Java Developers John Zukowski show you how to customize the output by replacing the default behavior. He is also compared to the old way to customize the output of ThreadGroup and the new way to customize the output by providing its own UNCAUGHTEXCEPTIONHANDLER.
Although we don't want to create a program that throws running time when it is not expected, this situation still happens - especially when running complex programs for the first time. These exceptions are typically handled using the default behavior, print stack overflow, and ending threads.
Where can I find the default behavior? Each thread belongs to a thread group represented by a java.lang.ThreadGroup class. As the name suggests, the thread group allows you to combine the thread. You may be in order to facilitate the combination of threads, for example, all threads in a thread pool belong to group X, and all threads of another pool belong to group Y, or combined threads for access control. The thread in group X does not have to access or change the thread in the group Y, unless they are all in the same thread group (or within a subgroup).
Before Tiger, the ThreadGroup class provides a method of processing unusually abnormal: ThreadGroup 's UNCAUGHTEXCEPTION () method. If the exception is not ThreadDeath, the name and stack backtrack of the thread are sent to System.err. But Tiger adds another method: Thread.uncaughTexceptionHandler interface. Dividing ThreadGroup or installation of the new interface is allowed to change the default behavior. We will conduct research on the methods provided before Tiger.
When the custom behavior of ThreadGroup occurs an unpreciated exception, the default behavior is to output the stack overflow to the system.err, as shown in Listing 1. No need to use any command parameters to start the program.
Listing 1. Thread overflow example
Public class simpledump {
Public static void main (string args []) {
System.out.println (Args [0]);
}
}
Running the program without any parameters will generate the output in Listing 2. Although it is not a long stack track, it is a complete stack tracking.
Listing 2. Default thread overflow output
Exception in thread "main" java.lang.ArrayIndexOutofboundsexception: 0
AT SimpleDump.main (SimpleDump.java: 3)
As the Java platform is the same, if you don't like the default behavior, you can make changes. In the previous version of the Tiger version of the Java platform, you cannot replace the default behavior of all threads, but you can create a new THREADGROUP and change the default behavior of any thread created in that group. You can rewrite the UncaughTexception (Thread T, Throwable E) method to customize the behavior. Then, any thread created within the thread group will receive new behavior when an unpredictable runtime exception occurs. However, it is best to fix the infrastructure, I will provide a simple example to illustrate the steps necessary to change the default behavior. Listing 3 shows the adjusted test procedures that will be put into the new thread:
Listing 3. Adjustable thread overflow example public class windowdump {
Public static void main (string args []) throws exception {
ThreadGroup group = new loggingthreadgroup ("logger");
New Thread (Group, "Mythread") {
Public void run () {
System.out.println (1/0);
}
} .start ();
}
}
The LoggingThreadGroup class is a new content, and its definition is displayed in Listing 4. For explanation, the special behavior implemented by rewriting the uncaughtexception () method will display this exception in a pop-up window, which is done with the Java Logging API with the help of special handler.
Listing 4. Definition of LoggingThreadGroup
Import java.util.logging. *;
Public class loggingthreadgroup extends threadgroup {
Private static logger logger;
Public loggingthreadgroup (String name) {
Super (Name);
}
Public void UncaughTexception (Thread T, Throwable E) {
// Initialize Logger ONCE
IF (Logger == Null) {
Logger = Logger.getlogger ("eXample");
Handler handler = loggingWindowhandler.getInstance ();
Logger.addhandler (Handler);
}
Logger.log (level.warning, t.getname (), e);
}
}
The type of custom Handler created here is LoggingWindowHandler, which is defined in Listing 5. The handler uses a support class LoggingWindow that will be exceptionally displayed on the screen. The definition of this class is displayed in Listing 6. Handler's Public Void Publish (LogRecord Record) method has implemented some important operations. Most of the rest are only related to the configuration.
Listing 5. Definition of LoggingWindowHandler
Import java.util.logging. *;
Public class loggingwindowhandler extends handler {
Private static loggingwindow window;
Private static loggingWindowhandler Handler;
Private loggingwindowhandler () {
CONFIGURE ();
Window = New LoggingWindow ("Logging Window ...", 400, 200);
}
Public static synchronized loggingWindowhandler getInstance () {
IF (Handler == NULL) {
Handler = new loggingwindowhandler ();
}
Return Handler;
}
/ **
* GET Any Configuration Properties Set
* /
Private vid configure () {
Logmanager manager = logmanager.getlogmanager (); string classname = getClass (). Getname ();
String level = manager.getProperty (classname ".level");
Setlevel ((Level == null)? level.info: level.parse (level);
String filter = manager.getProperty (classname ".filter);
SetFilter (Makefilter (Filter);
String formatter =
Manager.getproperty (classname ".formatter");
SetFormatter (Makeformatter (formatter);
}
Private filter makefilter (String name) {
Filter f = NULL;
Try {
Class C = Class.Forname (Name);
f = (filter) c.newinstance ();
} catch (exception e) {
IF (name! = null) {
System.err.Println ("Unable to load filter:" name);
}
}
Return F;
}
Private formatter makeformatter (String name) {
Formatter f = null;
Try {
Class C = Class.Forname (Name);
f = (formatter) c.newinstance ();
} catch (exception e) {
f = new simpleformatter ();
}
Return F;
}
// Overridden Abstract Handler Methods
Public void close () {
}
Public void flush () {
}
/ **
* If Record is loggable, format it and add it to window
* /
Public void publish (Logrecord Record) {
String message = null;
IF (Isloggable (Record) {
Try {
Message = getformatter (). Format (Record);
} catch (exception e) {
ReportError (null, e, errorManager.format_failure);
Return;
}
Try {
WINDOW.ADDLoginfo (Message);
} catch (exception e) {
ReportError (NULL, E, ErrorManager.write_failure);
}
}
}
}
Listing 6. Definition of LoggingWindow
Import java.awt. *;
Import javax.swing. *;
Public class loggingwindow extends jframe {
Private Jtextarea Textarea;
Public loggingWindow (String Title, Final Int Width,
Final Int height) {
Super (title);
Eventqueue.invokelater (New Runnable () {public void run () {
Setsize (width, height);
Textarea = new jtextAREA ();
JscrollPane Pane = New JscrollPane (Textarea);
TextArea.setedITable (FALSE);
getContentPane (). Add (PANE);
SetVisible (TRUE);
}
});
}
Public void addloginfo (final string data) {
Eventqueue.invokelater (new runnable () {
Public void run () {
TextArea.Append (data);
}
});
}
}
The WindowDUMP program in Listing 3 will appear in Figure 1. Since the console handler is not removed from the Logger, the stack overflow will still appear on the console.
Figure 1. Record stack tracking
When running an abnormality, you may have to make a lot of work to change the problem. Most of the code is logging handler, but to perform changes, you must subdivide ThreadGroup to override UncaughTexception () and then perform your thread in the thread group. However, let's take a look at Tiger's processing by just install Thread.uncaughTexceptionHandler.
Using the custom behavior of UNCAUGHTEXCEPTIONHANDLER Add a new public internal class UncaughTexceptionHandler to Tiger, Thread class definition, a more complete name is Thread.uncaughTexceptionHandler (complete names you need to use when accessing internal classes). The definition of the interface is a method, as shown in Figure 7:
Listing 7. Definition of UNCAUGHTEXCEPTIONHANDLER
Public interface thread.uncaughtexceptionhandler {
Public void uncaughtexception (thread, throwable);
}
You may not notice that the method in Listing 7 is the same as the method of ThreadGroup wever rewritten. In fact, this interface is now implemented by the ThreadGroup class.
New internal classes can help us understand the following two pairs of methods and help us use them in Thread:
GetUncaughtexceptionHandler () and setUncaughtexceptionhandler (). getDefaultuncaughTexceptionHandler () and SetDefaultuncaughTexceptionHandler ().
The first pair method is GetUncaughTexceptionHandler () and setUncaughtexceptionHandler (), which allows you to customize behavior for current threads and proceeds, allowing twenty or more threads to have their own custom behavior. However, you can more likely to use the second pair of methods getDefaultuncaughTexceptionHandler () and setDefaultuncaughtexceptionhandler (). If you use the second pair method to set the default handler, all threads without your own exception handler will use the default handler.
It seems to be very simple. For the explanation, the Listing 8 converts the ThreadGroup-friendly program in Listing 3, using the new UncaughTexceptionHandler interface: List 8. UncaughtexceptionHandler example
Public class handlerdump {
Public static void main (string args []) throws exception {
Thread.uncaughtexceptionHandler Handler = New LoggingthreadGroup ("Logger");
Thread.currentthread (). Setuncaughtexceptionhandler (Handler);
System.out.println (1/0);
}
}
The program only uses LoggingThreadGroup to uncaughteexceptionHandler, and does not create new handler implementations. Please note that the new code is much simpler than the original code.
Other Thread Change The Thread class not only supports the unfailed exception handler for Tiger added, but also supports the stack tracking of all valid threads using getallStackTraces (), or supports only the stack tracking of the current thread using GetStackTrace (). Both stack tracks return to types of java.lang.StackTraceElement, java.lang.stackTraceElement is a class added in the Java 1.4 platform, which allows you to generate your stack trace. At the same time, the new features of the Java 5 platform is a unique thread identifier (you can use GetId () to get the identifier) and a new Thread.State class, and the GetThreadState () method associated with this class. The last thread change is a state enumeration table that is used to monitor the system status, not to synchronize.
End a position to add a simple library change such as an unpreciated exception handler, which can greatly increase the understandability of the original code. Although in the thread group level, the function of the new library code is the same as the original library code, but the ease of use and flexibility in the new model far exceeds the time required to adjust the code as an update. Of course, the old method can still be used, but it is best to update the code to the latest library function.