Using the "Mark Occurrences" Feature of Eclipse for Reading Java Methods
Not all methods are created equal. Some are brief and simple while others are long long and complex. Regardless of what Javadoc may be available to know what a method really does one needs to dig in the code. It is fair to say we spend a good chunk of time doing just that.
So how much help do we get from IDE's today? Navigating code structure such as packages and classes is quite common. So is the ability to get to a class by typing its name. However, once we find a class or a method we get no further help to comprehend its logic.
Some tools go as far as to generate an UML sequence diagram from code but that isn't practical to use all the time and can get confusing as methods get longer.
In this article I will combine a simple feature of Eclipse with a consistent approach to create an effective technique for quickly understanding what a method does.
Introducing Mark Occurrences
"Mark Occurrences" is a very simple and self-evident feature. When working in a Java editor, turn on "Mark Occurrences" in the toolbar () or press Alt+Shift+O. Then press on a variable, method, or type to see where it is referenced. What you will see are the highlighted usages of that variable, method or type.
The "Mark Occurrences" button can be toggled on and off. While it is on, clicking on a variable will highlight its usages. Click on a diferent variable and the highlights will change. The basic idea is very simple. Here are a couple of less known applications of this feature:
- Select a method's return type to see all exit points
- Select an exception to see where it's thrown
- Fine tune "Mark Occurrences" via Window > Preferences > Java > Editor > Mark Occurrences...
Using the Feature
All this is easy to understand. So you might wonder what else is there to talk about? This is where I'd like to combine the "Mark Occurrences" feature with a little bit of OO theory to turn it into an effective approach reading the logic of a method.
To do this let's define the possible effects of a method. There are many things a method can do. However, in terms of its effects it really comes down to this. A method can:
- modify its own state (i.e. alter a member variable)
- modify the state of other objects (typically passed as input parameters)
- initiate calls or modify the state of external systems such as a database, file system, etc.
With this knowledge in mind I will demonstrate how we can quickly find what methods do without having to understand every line of code. What follows are a couple of alternative approaches that you can apply depending on whether the method accepts input or not.
Tracing Input Parameters
Most methods rely on input parameters. When present input parameters are accepted and logic is executed conditionally depending on the parameter values. Hence a good place to begin reading a method is to click on an input parameter with "Mark Occurrences" toggled on. This is shown below.
To the right is a method from the java.awt.EventQueue class, which accepts a Runnable object as an input parameter.
Clicking on the runnable input parameter shows that it is used to construct an InvocationEvent.
Our next question is what happens to the InvocationEvent? To find out we click on the event variable (see Step 2 below).
To the right is the same method from java.awt.EventQueue. Clicking on the event variable shows it is used (a) to post an event on the awt queue and (b) to check if the event contains any exceptions.
That's it! In two steps we got to the bottom of what the method does. We know now it alters the state of the awt queue by posting an InvocationEvent.
Surely the method there is more to this method than that - for example there is the call to lock.wait() but in terms of effects we now what impact the method can have. In my experience more often we need to know the effects of a method than how exactly it does it.
Please note this technique works for longer methods too. In fact the longer the method the larger the benefit. This is especially true when we need to work our way through loops and conditional statements where potentially many more steps might be required to find out a method's effects.
What if a method doesn't take input parameters? In this case we can begin by tracing all exit points. We do this by clicking on a method's return type (works when the return type is void too).
In the code snippet to the right taken from java.awt.EventQueue the cursor is placed on AWTEvent in the method declaration (line 319).
What is see that the method can exit by (a) returning an AWTEvent on line 335, (b) throwing an InterruptedException on line 339, and (c) by reaching the end of the method line 342 (actually examining the while loop condition shows that line 342 can never be reached so we quickly dismiss that option!)
The next question is where does the equ variable on line 335 come from? To answer that we click on the eqi variable (shown in Step 2).
In the code snippet to the right the cursor is placed on the eqi variable. This shows us that the eqi variable is part of an array of internally maintained EventQueueItem objects.
In two steps we have found what we are looking for! What we know now is that the getNextEvent method returns an AWTEvent object that originates from an internal array of EventQueueItem objects - that is to say an array of queues.
Yes, there is more this method that that but we've a summary that will suit us in most cases.
"Mark Occurrences" is a simple feature that is very self-evident after it's been used once. However, in my mind this simple feature can be turned into a tool that is more powerful than is obvious at first. Hopefully with this I've been able to convince you of that.
So if you're like me and dislike deciphering long convoluted methods, next time try using this technique to get to the bottom of what you need to know in a few clicks.