Debugging Tips Core Java

Suppose you wrote your program and made it bulletproof by catching and properly handling all exceptions. Then you run it, and it does not work right. Now what? (If you never have this problem, you can skip the remainder of this section.)

Of course, it is best if you have a convenient and powerful debugger. Debuggers are available as a part of professional development environments such as Eclipse and NetBeans.

We discuss the debugger later in this chapter. In this section, we offer you a number of tips that may be worth trying before you launch the debugger.

  1. You can print or log the value of any variable with code like this:

    If x is a number, it is converted to its string equivalent. If x is an object, then Java calls its toString method. To get the state of the implicit parameter object, print the state of the this object.

    Most of the classes in the Java library are very conscientious about overriding the toString method to give you useful information about the class. This is a real boon for debugging. You should make the same effort in your classes.

  2. One seemingly little-known but very useful trick is that you can put a separate main method in each class. Inside it, you can put a unit test stub that lets you test the classin isolation.

    Make a few objects, call all methods, and check that each of them does the right thing. You can leave all these main methods in place and launch the Java virtual machine separately on each of the files to run the tests. When you run an applet, none of these main methods are ever called. When you run an application, the Java virtual machine calls only the main method of the startup class.

  3. If you liked the preceding tip, you should check out JUnit from http://junit.org. JUnit is a very popular unit testing framework that makes it easy to organize suites of test cases. Run the tests whenever you make changes to a class, and add another test case whenever you find a bug.
  4. A logging proxy is an object of a subclass that intercepts method calls, logs them, and then calls the superclass. For example, if you have trouble with the setBackgroundmethod of a panel, you can create a proxy object as an instance of an anonymoussubclass:

    Whenever the setBackground method is called, a log message is generated. To find out who called the method, generate a stack trace.

  5. You can get a stack trace from any exception object with the printStackTrace method in the Throwable class. The following code catches any exception, prints the exception object and the stack trace, and rethrows the exception so it can find its intended handler.

    You don’t even need to catch an exception to generate a stack trace. Simply insert the statement

    anywhere into your code to get a stack trace.

  6. Normally, the stack trace is displayed on System.err. You can send it to a file with the void print Stack Trace(PrintWriter s) method. Or, if you want to log or display the stack trace, here is how you can capture it into a string:
  7. It is often handy to trap program errors in a file. However, errors are sent to System.err, not System.out. Therefore, you cannot simply trap them by running

    This works in bash and the Windows shell.

  8. Having stack traces of uncaught exceptions show up in System.err is not ideal. These messages are confusing to end users if they happen to see them, and they are not available for diagnostic purposes when you need them. A better approach is to logthem to a file. As of Java SE 5.0, you can change the handler for uncaught exceptionswith the static Thread.set Default Uncaught ExceptionHandler method:
  9. This can occasionally be helpful to diagnose class path problems.

  10. If you ever looked at a Swing window and wondered how its designer managed to get all the components to line up so nicely, you can spy on the contents. Press CTRL+SHIFT+F1, and you get a printout of all components in the hierarchy:
  11. If you design your own custom Swing component and it doesn’t seem to be displayed correctly, you’ll really love the Swing graphics debugger. And even if you don’t write your own component classes, it is instructive and fun to see exactly how the contents of a component are drawn. To turn on debugging for a Swing component, use the setDebug Graphics Options method of the JComponent class. The following options are available:
  12. We have found that for the flash option to work, you must disable “double buffering,” the strategy used by Swing to reduce flicker when updating a window. The magic incantation for turning on the flash option is Repaint Manager .current Manager get Root Pane()) .set Double Buffering Enabled (false);

    Simply place these lines at the end of your frame constructor. When the program runs, you will see the content pane filled in slow motion. Or, for more localized debugging, just call setDebugGraphicsOptions for a single component. Control freaks can set the duration, count, and color of the flashes—see the on-line documentation of the Debug Graphics class for details.

  13. Java SE 5.0 added the -Xlint option to the compiler for spotting common code problems. For example, if you compile with the command javac -Xlint:fallthrough then the compiler reports missing break statements in switch statements. (The term“lint” originally described a tool for locating potential problems in C programs, andis now generically applied to tools that flag constructs that are questionable but notillegal.)

    The following options are available:

  14. . Java SE 5.0 added support for monitoring and management of Java applications, allowing the installation of agents in the virtual machine that track memory consumption, thread usage, class loading, and so on. This feature is particularly important for large and long-running Java programs such as application servers. As a demonstration of these capabilities, the JDK ships with a graphical tool called jconsolethat displays statistics about the performance of a virtual machine . Find out the ID of the operating system process that runs the virtual machine.

The jconsole program

The jconsole program

In UNIX/Linux, run the ps utility; in Windows, use the task manager. Then launch the jconsole program:

NOTE: Prior to Java SE 6, you need to launch your program with the -Dcom.sun.management.jmxremote option:

You can use the jmap utility to get a heap dump that shows you every object on the heap. Use these commands:

Then, point your browser to localhost:7000. You will get a web application that letsyou drill down into the contents of the heap at the time of the dump.

If you launch the Java virtual machine with the -Xprof flag, it runs a rudimentary profiler that keeps track of the methods in your code that were executed most often. Theprofiling information is sent to System.out. The output also tells you which methodswere compiled by the just-in-time compiler.

Using a Console Window

When you debug an applet, you can see error messages in a window: In the configuration panel of the Java Plug-in, check the Show Java Console box. The Java Console window has a set of scrollbars, so you can retrieve messages that have scrolled off the window. Windows users will find this a definite advantage over the DOS shell window in which the System.out and System.err output normally appears.

We give you a similar window class so you can enjoy the same benefit of seeing your debugging messages in a window when debugging a program. Figure below shows our ConsoleWindow class in action.The class is easy to use. Simply call

Then print to System.out or System.err in the normal way.

The console window

The console window

Listing below lists the code for the ConsoleWindow class. As you can see, the class is quite simple. Messages are displayed in a JTextArea inside a JScrollPane. We call the System.setOut and System.setErr methods to set the output and error streams to a special stream that adds all messages to the text area.

ConsoleWindow.java

Tracing AWT Events

When you write a fancy user interface in Java, you need to know what events AWT sends to what components. Unfortunately, the AWT documentation is somewhat sketchy in this regard. For example, suppose you want to show hints in the status line when the user moves the mouse over different parts of the screen. The AWT generates mouse and focus events that you may be able to trap.

We give you a useful EventTrace class to spy on these events. It prints out all event handling methods and their parameters. See Figure below for a display of the traced events.

The EventTracer class at work

The EventTracer class at work

To spy on messages, add the component whose events you want to trace to an event tracer:

That prints a textual description of all events, like this:

You may want to capture this output in a file or a console window, as explained in the preceding sections.

Listing below is the EventTracer class. The idea behind the class is easy even if the implementation is a bit mysterious. Here are the steps that are carried out behind the scenes:

  1. When you add a component to the event tracer in the add method, the JavaBeans introspection class analyzes the component for methods of the form void addXxx-Listener(XxxListener). For each matching method, an EventSetDescriptor is generated. We pass each descriptor to the addListener method.
  2. If the component is a container, we enumerate its components and recursively call add for each of them.
  3. The addListener method is called with two parameters: the component on whoseevents we want to spy and the event set descriptor. The getListenerType method of the EventSetDescriptor class returns a Class object that describes the event listener interface such as ActionListener or ChangeListener. We create a proxy object for that interface. The proxy handler simply prints the name and event parameter of the invoked event method. The getAddListenerMethod method of the EventSetDescriptor class returns a Method object that we use to add the proxy object as the event listener to the component.

This program is a good example of the power of the reflection mechanism. We don’t have to hardwire the fact that the JButton class has a method addActionListener whereas a JSlider has a method addChangeListener. The reflection mechanism discovers these facts for us.

Letting the AWT Robot Do the Work

Java SE 1.3 added a Robot class that you can use to send keystrokes and mouse clicks to any AWT program. This class is intended for automatic testing of user interfaces. To get a robot, you need to first get a GraphicsDevice object. You get the default screen device through the sequence of calls:

The idea is that you simulate key and mouse input and afterwards take a screen snapshot to see whether the application did what it was supposed to. You capture the screen with the createScreenCapture method:

Finally, you usually want to add a small delay between robot instructions so that the application can catch up. Use the delay method and give it the number of milliseconds to delay. For example:

The program ends by taking a screen capture and displaying it in another frame As you can see from this example, the Robot class is not by itself suitable for convenient user interface testing. Instead, it is a basic building block that can be a foundational part of a testing tool. A professional testing tool can capture, store, and replay user interaction scenarios and find out the screen locations of the components so that mouse clicks aren’t guesswork. Hopefully, as Java applications are becoming more popular, we will see more sophisticated testing tools.

Capturing the screen with the AWT robot

Capturing the screen with the AWT robot

java.awt.GraphicsEnvironment 1.2

  • static GraphicsEnvironment getLocalGraphicsEnvironment()

    returns the local graphics environment.

  • GraphicsDevice getDefaultScreenDevice()

    returns the default screen device. Note that computers with multiple monitors have one graphics device per screen use the getScreenDevices method to obtain an array of all screen devices.

java.awt.Robot 1.3

  • Robot(GraphicsDevice device)

    constructs a robot that can interact with the given device.

  • void keyPress(int key)
  • void keyRelease(int key)

simulates a key press or release.

  • void mouseMove(int x, int y)

simulates a mouse move.

  • void mousePress(int eventMask)
  • void mouseRelease(int eventMask)

simulates a mouse button press or release.

Parameters: key The key code. See the KeyStroke class for more information on key codes

Parameters: x, y The mouse position in absolute pixel coordinates Parameters: eventMask The event mask describing the mouse buttons. See the InputEvent class for more information on event masks

  • void delay(int milliseconds)

delays the robot for the given number of milliseconds.

  • BufferedImage createScreenCapture(Rectangle rect)

captures a portion of the screen.



Face Book Twitter Google Plus Instagram Youtube Linkedin Myspace Pinterest Soundcloud Wikipedia

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Core Java Topics