Refactoring in NetBeans 4.1

   
By Robert Eckstein, May 2005  

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:

  1. 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.
  2. 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:

  1. Create method getResult check box. Leave this selected.
  2. Create method setResult. We don't want this method because it's redundant. Clear this check box.
  3. AddFunction() ... result = first + second. Refactoring won't help us here. Leave this check box clear.
  4. 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.
  5. 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

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.