Refactoring in NetBeans 4.1
The term
refactoring simply means changing the structure of your source code. For example, you may decide to change the name of a class, a method, or a field inside one of your source files. Or perhaps you need to move a class from one package to another. Or you can add a parameter to a frequently called method and use a default value wherever it is invoked throughout your source. In short, refactoring is generally about making source better, including
- Improving the code's legibility and maintainability
- Making your source code more portable and reusable
- Implementing a design change due to a new software feature
- Cleaning up that 1.0 product that the developer finished the midnight before
Depending on the tools you use, refactoring can be either time-consuming or quick and easy. Fortunately, NetBeans comes with a solid amount of refactoring support built in. This article aims to teach you about some of the more common refactoring options, as well as to show you ways to use these options in everyday situations with your Java technology source code. NetBeans presently supports four primary refactoring approaches:
- Renaming fields, methods, classes, or packages
- Encapsulating fields
- Changing method parameters
- Moving classes
You can select these options from the Refactoring menu at the top of the NetBeans IDE, from context-sensitive menus inside the editor, or by automatically invoking them from selective actions inside the Projects window.
Additional refactoring support in NetBeans is also in the works. You can view a listing at
http://refactoring.netbeans.org/. Here are some refactoring features coming in future versions of NetBeans.
- Extract interface/superclass
- Pull up, push down method
- Inline method
- Extract method
- Move method
- Convert nested to top-level class
- Extract/inline local variable
Some Sample Source Code
Before we go any further, let's start off with some source code that's ripe for refactoring. You can download this source code using the link at the end of the article. First, for
Main.java:
package sample;
import sample.Adder;
public class Main {
public Main() {
Adder a = new Adder(4,5);
System.out.println("4 + 5 = " + a.firstPlusSecond);
}
public static void main(String[] args) {
Main m = new Main();
}
}
|
And here is the source code for
Adder.java, a class that adds two integers.
package sample;
public class Adder {
public int firstPlusSecond;
private int first;
private int second;
public Adder(int arg1, int arg2) {
first = arg1;
second = arg2;
firstPlusSecond = first + second;
}
public String toString() {
return Integer.toString(firstPlusSecond);
}
}
|
After creating these classes in NetBeans 4.1 using the template for a standard Java application, you should have a project that looks like Figure 1.
|
Figure 1: The Sample Project in NetBeans 4.1
Click
here for a larger image
|
|
At this point, let's say that you've inherited this source code after the previous programmer left the company and that you need to add more functionality (for example, classes that subtract, multiply, and divide). Clearly, we need to get this source ready to handle enhancements.
Simple Refactoring: Renaming a Package
With NetBeans 4.1, you can use the built-in refactoring tools to change the name of a field, a method, a class, or even a package. This change will then propagate throughout the source tree to all the classes that reference that particular item, instead of forcing you to hunt down references by yourself or through compilation errors. Each of these tools is listed under the Refactor menu at the top of the NetBeans IDE. Note: Don't confuse this with the RefactorIT menu, if you have it, which is a separate plug-in.
For example, let's say that we don't like our source classes to be in the
sample package. Instead, we want them to reside in a package called
functions. First, we change the name of the folder in the Projects window in the upper-left corner. This will immediately bring up the dialog box shown in Figure 2.
|
|
Figure 2: The Refactoring Dialog Box
|
|
Note that the check box for Preview All Changes in the lower-left corner of the dialog box is selected. Leave it selected, and press Next. At this point, the preview of the refactoring tasks is displayed in the bottom output window of the IDE, as shown in Figure 3.
|
Figure 3: The Refactoring Preview in the NetBeans Output Window
Click
here for a larger image
|
|
You can review the refactoring information presented in the output window and select and clear various changes that the IDE proposes to make. If the changes look good, press the Do Refactoring button to save the modifications. Figure 4 shows the saved changes. Note that not only has the package been changed in the Projects window in the upper left, but the package declaration at the top of the source code has been changed from
sample to
functions as well.
|
Figure 4: The Resulting Changes in the IDE
Click
here for a larger image
|
|
Renaming Fields
Source code can often have inappropriate or misleading field names, especially after the code has been updated for new functionality. Renaming fields can be particularly helpful in keeping your source code legible. At this point, you may be wondering: "Why not just use the Replace All button in a text Replace dialog to change all the field names?" Here are a couple of reasons:
- If a field is public, you may want to refactor the field name when it is referenced in other source code files, or even configuration files and deployment descriptors.
- If the field name matches a common word that occurs somewhere else, such as in the comments, you may not want to change all those occurrences (either in the currentsource file or in other files that reference it).
Renaming fields in NetBeans is easy. In this example, let's change the name of the awkward
firstPlusSecond field to
result. After all, we may want to later create an abstract superclass for both binary and unary operators. In order to refactor the name of a field, simply place the insertion beam over the field in question and choose the Rename menu item from the Refactor menu at the top of the IDE. See Figure 5.
|
Figure 5: The Refactoring Dialog Box for a Field Name Change
Click
here for a larger image
|
|
Again, you can preview the changes as they appear. Note that one of changes that NetBeans suggests is in
Main.java, outside of the current Java source that you are editing.
|
Figure 6: The Refactoring Preview for the Field Name Change
Click
here for a larger image
|
|
You can rename methods as well by placing the insertion beam over the line containing the definition of the method and choosing Rename from the Refactor menu.
Next, let's change the name of the class from
Adder to
AddFunction. Figure 7 shows the preview for the refactoring. Note that when you change the class name, the resulting file name, the constructors, and all references to the class in other files are automatically changed as well. This is a huge time-saver when you consider that the alternative is to open each file of source code by hand and find and replace a target string.
|
Figure 7: The Refactoring Information for the Class Name Change
Click
here for a larger image
|
|
Encapsulating Fields
You can change the encapsulation of fields inside an object by choosing the Encapsulate Field menu item from the Refactoring menu. (Other IDEs sometimes call this
generating getters and setters.) In this case, we don't want the result field to be public. Let's change the field from public to private and create a
getResult() accessor. At this point, you'll see a dialog box similar to Figure 8.
|
|
Figure 8: The Refactoring Dialog Box for the Encapsulate Field Change
|
|
First, clear the check boxes for the
first and
second fields. Second, be sure to clear the check box Use Accessors Even When Field Is Accessible. Finally, press Next. You should see the resulting refactoring summary, as shown in Figure 9.
|
Figure 9: The Refactoring Information for the Encapsulate Field Change
Click
here for a larger image
|
|
Note that in Figure 9, NetBeans 4.1 wants to create public accessors,
getResult() and
setResult(), for our field now that we've changed the visibility from public to private. We don't really want the
setResult() method -- the result is calculated elsewhere, currently in the constructor. However, we'll take the
getResult() method. So let's do the following:
-
Create method getResult check box. Leave this selected.
-
Create method setResult. We don't want this method because it's redundant. Clear this check box.
-
AddFunction() ... result = first + second. Refactoring won't help us here. Leave this check box clear.
-
toString()...return Integer.toString(result);. This would change the reference to
result to the
getResult() accessor, whichis not needed. Leave this check box clear as well.
-
Main()...System.out.println("Public result field = " + a.result); This will need to change because we cannot reference the private field anymore. Instead, we must call on the
a.getResult() method to obtain the results. Leave the check box selected.
You can also use the
Encapsulate Fields options to give the private fields
first and
second both
get and
set accessors.
Note that we didn't select the option to
Use Accessors Even When the Field is Accessible. If we had selected that option in the initial refactoring dialog box, NetBeans would have selected options 3 and 4 in the list above. And if we had approved the change, it would have replaced references to
result inside of
AddFunction.java with the
getResult() accessor.
Finally, note that the
main() method now has a call to the
getResult() accessor, instead of referencing the now private field:
public Main() {
AddFunction a = new AddFunction(4,5);
System.out.println("4 + 5 = " + a.getResult());
}
|
Changing Method Parameters
With NetBeans, you can also change method parameters, again with the effect of having those changes propagate throughout the source code. This can be a little more involved, however. Obviously, you will need to add code inside of the method so that it can take advantage of the modified parameters, but you also have the ability to specify a default value for any source that calls that method, both inside and outside of the target source file. In this case, let's change the
toString() method to include a radix parameter, as shown in Figure 10. The preview is shown in Figure 11.
|
Figure 10: Refactoring Dialog Box for Modifying Method Parameters
Click
here for a larger image
|
|
|
Figure 11: Preview Options for Modifying Method Parameters
Click
here for a larger image
|
|
In
AddFunction.java, the following line was changed:
public String toString(int radix) {
return Integer.toString(result);
}
|
Note that if we had explicitly called
toString() inside of the
Main.java class, the invocation would have been replaced with our default value for the new parameter:
toString(10).
Moving Classes
Finally, we can move classes from one location to another using the NetBeans refactoring tools. In this case, let's create a new package called
functions.binary and move the
AddFunction class inside of it. Select the Move Class option from the Refactoring menu, which should give you the dialog box and preview options shown in Figures 12 and 13.
|
Figure 12: Move Class Refactoring Dialog Box
Click
here for a larger image
|
|
|
Figure 13: Move Class Refactoring Preview
Click
here for a larger image
|
|
Note that because
Main.java references the
AddFunction class, an import statement must now be added to the source code because they no longer reside in the same package.
Source Code
You can download the sample source code for this article
here.
For More Information
Books
- Probably the most canonical text on refactoring is
Refactoring: Improving the Design of Existing Code by Martin Fowler, Kent Beck, John Brant, William Opdyke, and Don Roberts (Addison-Wesley, 1999).
- More information on design patterns can be found in
Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (Addison-Wesley, 1995).
- Another good text on patterns with Java is
Head First Design Patterns by Eric and Elisabeth Freeman, with others (O'Reilly, 2005).
Web Sites
JavaOne