Explore refactoring functions in Eclipse JDT

This article describes the various refactorings available in Eclipse Java™ Development Tools (JDT), including what each refactoring does, when to use it, and how to use it. It also explores the refactoring script functionality in Eclipse, which allows library developers to share code refactorings with their clients.

Share:

Prashant Deva, Founder, Chronon Systems

Prashant DevaPrashant Deva is the founder of Chronon Systems, where he created the first time-traveling debugger for Java. He also provides Eclipse-related consulting. Previously he built and sold Java development tools.


developerWorks Contributing author
        level

24 November 2009

Also available in Japanese Portuguese

The refactoring functionalities in Eclipse make it a modern-day Java integrated development environment (IDE), rather than an ordinary text editor. Using refactoring, you can easily make changes to your code without worrying about breaking things somewhere else. With refactoring, you can write some code just to see if it works without worrying about how it looks, then use the refactoring tools to quickly and easily turn that code into clean and highly modularized code. This article describes and shows how to use some of the powerful refactoring functions available in Eclipse.

Refactoring types

Rename

Rename is probably the most-used refactoring in Eclipse. It allows you to rename variables, classes, methods, packages, folders, and almost any Java identifiers. When you rename an identifier, all references to that identifier are also renamed. The shortcut to invoke the Rename refactoring is Alt+Shift+R. When you invoke the shortcut on an identifier in the Eclipse editor, a small box displays within the editor itself where you can change the identifier name. When you press Enter, all references to that identifier are changed, too.

Move

You can use Move to move a class from one package to another. It physically moves the class to the folder corresponding to the package and also changes all references to the class to refer to the new package.

You can drag and drop a class to a new package in the Package Explorer view, and the refactoring will take place automatically.

Extract Local Variable

The Extract Local Variable refactoring allows you to assign the result of a Java expression to a new local variable. Use it to simplify a complex Java expression by quickly dividing it into multiple lines. Or, when editing code, type the expression first and use this refactoring to automatically create a new local variable to assign the result to. This is useful when the return value has a complex type because the type of the variable is automatically generated.

You can invoke this refactoring from the editor. After typing the expression you want assigned to a variable, press Ctrl+1 and select Assign statement to a local variable. A new variable with the appropriate type is created for you.

Extract Constant

The Extract Constant refactoring allows you to convert any number or string literal in your code to a static final field. After the refactoring, all uses of that number or string literal in the class refer to that field, instead of the number or string literal itself. This way, you can modify the number or string literal in just one place (the value of the field), instead of doing a search and replace throughout your code.

To use, select the number or string literal in the editor, press Ctrl+1 and select Extract to Constant.

Convert Local Variable to Field

As the name suggests, the Convert Local Variable to Field refactoring takes a local variable and converts it to a private field of the class. All references to the local variable after this refer to the field.

To use, select a local variable, press Ctrl+1 and select Convert Local Variable to Field.

Convert Anonymous Class to Nested

The Convert Anonymous Class to Nested refactoring takes an anonymous class and converts it to a nested class of the method that originally contained the anonymous class.

To use, place your cursor inside the anonymous class and select Refactor > Convert Anonymous Class to Nested from the menu. A dialog box displays, requesting the name of the new class. You can also set properties of the class, such as specifying whether access to it is public, protected, private, or default. You can also say whether the class is final, static, or a combination of both.

As an example, the code in Listing 1 uses an anonymous class to create a Thread Factory.

Listing 1. Before Convert Anonymous Class to Nested refactoring
void createPool() {
	threadPool = Executors.newFixedThreadPool(1, new ThreadFactory()
		{

			@Override
			public Thread newThread(Runnable r)
			{
				Thread t = new Thread(r);
				t.setName("Worker thread");
				t.setPriority(Thread.MIN_PRIORITY);
				t.setDaemon(true);
				return t;
			}

		});
}

The code in Listing 1 would be much neater if the anonymous class was placed separately as an inner class. Thus, I perform the Convert Anonymous Class to Nested refactoring, giving the name MyThreadFactory to the new class. This results in the code shown in Listing 2, which is much neater.

Listing 2. After Before Convert Anonymous Class to Nested refactoring
private final class MyThreadFactory implements ThreadFactory
	{
		@Override
		public Thread newThread(Runnable r)
		{
			Thread t = new Thread(r);
			t.setName("Worker thread");
			t.setPriority(Thread.MIN_PRIORITY);
			t.setDaemon(true);
			return t;
		}
	}
void createPool(){
	threadPool = Executors.newFixedThreadPool(1, new MyThreadFactory());
}

Convert Member Type to Top Level

The Convert Member Type to Top Level refactoring takes a nested class and converts it to a top-level class with its own Java file.

To use this refactoring, place your cursor inside a nested class and select Refactor > Convert Member Type to Top Level. If the nested class is a static class, a box showing a preview of the refactoring displays right away. If it is not a static class, you first need to declare the name of the field that will hold the reference to the parent class of the nested class before you get to the preview box. You can also declare the field as final in this box.

Extract Interface

The Extract Interface refactoring makes an interface out of the methods defined in a class.

To use this refactoring, select Refactor > Extract Interface from the menu. A dialog box displays, requesting the name of the new interface. You can check the methods from the class that will be declared in the interface. The dialog box also allows you to convert all valid references to the class to references to the interface Note that the refactoring only converts valid references to the class to the new interface type. That means if you don't select a method of the class to be part of the interface and Eclipse detects that a reference to a class uses that method, that reference won't be converted to the new interface type. Keep this in mind so you don't make the mistake of thinking that all references to a class have been changed to the new interface type.

Extract Superclass

The Extract Superclass refactoring is similar to the Extract Interface refactoring described earlier. However, the Extract Superclass extracts a superclass instead of an interface. If the class already uses a superclass, the newly generated superclass will have that class as its superclass, maintaining the class hierarchy.

To use this refactoring, make sure your cursor is on one of the method declarations or fields of the class and select Refactor > Extract Superclass. The dialog box that displays is similar to the Extract Interface dialog box and allows you to name the new superclass and select the methods and fields that will be put in the superclass.

A huge difference between extracting a superclass and extracting an interface is that the methods put in the superclass are actually moved there. So, if any of those methods contain references to any fields in the original class, you get a compiler error because they are invisible to the superclass. The best remedy in this case is to move those referenced fields to the superclass, too.

Extract Method

The Extract Method refactoring allows you to select a block of code and convert it to a method. Eclipse automatically infers the method arguments and return types.

This is useful when a method is too big and you want to subdivide blocks of it into different methods. It is also useful if you have a piece of code that is reused across many methods. When you select one of those blocks of code and do a refactoring, Eclipse finds other occurrences of that block of code and replaces it with a call to the new method.

To use this refactoring, select a block of code in the editor and press Alt+Shift+M. A dialog box displays, requesting the name and visibility (public, private, protected, or default) of the new method. You can even change the parameters and return types. The new method is created with the selected block of code in it refactored to properly use the argument and return values of the new method. The method from which the refactoring was originally done now contains a call to the new method.

For example, say I want to move the block of code after the call to map.get() in Listing 3 to a separate method.

Listing 3. Before Extract Method refactoring
@Override
	public Object get(Object key)
	{
		TimedKey timedKey = new TimedKey(System.currentTimeMillis(), key);
		Object object = map.get(timedKey);

		if (object != null)
		{
			/** 
			 * if this was removed after the 'get' call by the worker thread
			 * put it back in
			 */
			map.put(timedKey, object);
			return object;
		}

		return null;
	}

To do so, I select the block of code in the editor and press Alt+Shift+M. I set the name of the new method as putIfNotNull(), and Eclipse produces the code in Listing 4, automatically figuring out the correct arguments and return values.

Listing 4. After Before Extract Method refactoring
@Override
	public Object get(Object key)
	{
		TimedKey timedKey = new TimedKey(System.currentTimeMillis(), key);
		Object object = map.get(timedKey);

		return putIfNotNull(timedKey, object);
	}

	private Object putIfNotNull(TimedKey timedKey, Object object)
	{
		if (object != null)
		{
			/** 
			 * if this was removed after the 'get' call by the worker thread
			 * put it back in
			 */
			map.put(timedKey, object);
			return object;
		}

		return null;
	}

Inline

The Inline refactoring can inline a reference to a variable or method. When used, it replaces the reference to the variable or method with the value assigned to the variable or the implementation of the method, respectively. This can be useful for cleaning up your code in the following situations:

  • When a method is called only once by another method, and it makes more sense as a block of code.
  • When an expression looks cleaner on one line, rather than split into multiple lines by assigning values to different variables.

To use this refactoring, place the cursor on a variable or method and press Alt+Shift+I. A dialog box displays asking you to confirm the refactoring. If you're refactoring a method, the dialog box also gives you the option of deleting the method altogether after performing the refactoring.

For example, the second line in Listing 5 just assigns the value of an expression to the timedKey variable.

Listing 5. Before Inline refactoring
public Object put(Object key, Object value)
	{
		TimedKey timedKey = new TimedKey(System.currentTimeMillis(), key);
		return map.put(timedKey, value);
	}

Listing 6 shows the same code after I used the Inline refactoring. Note that what was previously two lines of code now fits neatly into a single line of code.

Listing 6. After Inline refactoring
@Override
	public Object put(Object key, Object value)
	{
		return map.put(new TimedKey(System.currentTimeMillis(), key), value);
	}

Change Method Signature

The Change Method Signature refactoring allows you to change the signature of a method. It modifies all calls to that method to use the new signature.

To use this refactoring, select Refactor > Change Method Signature. The dialog box shown in Figure 1 displays, allowing you to change everything about the method, including adding or removing parameters, changing the order of the parameters, changing the return value type, adding exceptions to the declaration of the method, and even changing the name of the method.

Figure 1. The Change Method Signature dialog box
Figure 1 displays, allowing you to change everything about the method, including adding or removing parameters, changing the order of the parameters and more

Note that some modifications you make to the method, such as adding a parameter or changing a return type, may cause the refactored code to contain compiler errors because Eclipse doesn't know what to enter for those new parameters.

Infer Generic Type Arguments

The Infer Generic Type Arguments refactoring automatically tries to guess the appropriate generic types for classes used in their raw form. This refactoring is generally used to convert pre-Java 5 code to Java 5 and later code.

This refactoring can even be invoked from the Package Explorer. Simply right-click on any project, package, or class in the Package Explorer and select Refactor > Infer Generic Type Arguments.

The code in Listing 7 shows a ConcurrentHashMap that can take Generic Type Arguments. However, the code in Listing 7 doesn't specify the type parameters.

Listing 7. Before Infer Generic Type Arguments refactoring
private final ConcurrentHashMap map = new ConcurrentHashMap();

After I use the Infer Generic Type Arguments refactoring, Eclipse automatically determines the correct type parameters and produces the code shown in Listing 8.

Listing 8. After Infer Generic Type Arguments refactoring
private final ConcurrentHashMap<TimedKey, Object> map = 
     new ConcurrentHashMap<TimedKey, Object>();

Migrate JAR File

The Migrate JAR File refactoring allows you to easily upgrade Java Archive (JAR) files on a project's build path. The usual way to upgrade a JAR file on the build path with a new version is to do the following:

  1. Go to the project's properties and remove the existing JAR file from the build path.
  2. Manually delete the JAR file from its folder.
  3. Copy the new JAR file, renaming it to reflect the name by which it is referenced in all the build scripts.
  4. Add the new JAR file to the build path manually.

The Migrate JAR File refactoring allows you to do all this in one step. To invoke the refactoring, select Refactor > Migrate Jars. In the dialog box that displays, select the location of the new JAR file. In the tree below, select the JAR from the project that will be upgraded to the new version. If you select the Replace Jar file contents but preserve existing filename checkbox, the new JAR file is renamed to match the name of the old JAR file, thus not breaking any build scripts that refer to the JAR file by that name. In any case, when you click Finish, the previous JAR file is deleted, and the new JAR file is copied to its location and automatically added to the project's build path, making your project use the new JAR file.

Refactoring scripts

Refactoring scripts allow you to export and share refactoring actions. This is extremely useful when you are about to distribute a new version of a library that can cause errors for people using the older version. By distributing a refactoring script along with the library, the people who are using the older version can simply apply the script to their projects to make their code use the new version of the library.

To create a refactoring script, go to Refactor > Create Script. The window shown in Figure 2 displays, showing the history of all the refactorings that have been performed in the workspace. Select the ones you need, specify a location for the script to be generated, then click Create to generate the script.

Figure 2. The Create Script window
Figure 2 displays, showing the history of all the refactorings that have been performed in the workspace

To apply an existing refactoring script to your workspace, select Refactor > Apply Script. In the dialog box that displays, select the location of the script. Click Next to see the refactorings that this script will perform, then click Finish to apply the refactorings.

As an example, suppose the com.A class is renamed com.B in version 2 of your JAR file. Because people using version 1 of your JAR file have references to com.A in their code, simply upgrading to the new version of the library will break their existing code. However, you can distribute a refactoring script with your JAR file that automatically renames references to com.A class to com.B, allowing people to easily upgrade to the new version of your JAR file.

Conclusion

With the various refactorings available in Eclipse, it is easy to transform an ugly piece of code into a beautiful, artistic one. Refactoring scripts allow you to easily upgrade your applications without worrying about clients having to spend hours looking through documentation to figure out what broke their code. Eclipse's refactoring functionalities truly put it ahead of other text editors and IDEs.

Resources

Learn

Get products and technologies

Discuss

  • The Eclipse Platform newsgroups should be your first stop to discuss questions regarding Eclipse. (Selecting this will launch your default Usenet news reader application and open eclipse.platform.)
  • The Eclipse newsgroups has many resources for people interested in using and extending Eclipse.
  • Participate in developerWorks blogs and get involved in the developerWorks community.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=447596
ArticleTitle=Explore refactoring functions in Eclipse JDT
publish-date=11242009