Eclipse has various refactoring functions, but to be honest, I didn't really understand what would happen if I executed it, so I summarized it.
Refactoring is the process of improving the internal structure of software while preserving its external behavior.
There is no perfect design. Strictly speaking, it seems perfect at the time of design, but it becomes less perfect over time. Furthermore, no one knows what kind of requests will come out in the future and who will add functions where.
An example where the design is not perfect
――I was thinking of only cash and credit cards as payment methods, but now it is necessary to support other cashless payments. ――Since the delivery time was short, we took ad hoc measures to limit the range of influence. --A new participant adds code without understanding the existing code and becomes spaghetti code.
As the design deteriorates over time, it is necessary to perform regular maintenance.
Well-organized code is highly readable and can reduce the time it takes developers to read the code. In addition, it makes it easier to find bugs.
If the design is not good, technical debt will be accumulated, the same change will be applied to many places, the extent of influence will not be known, and the investigation will take time. By continuously refactoring, debt is eliminated, and even if the number of functions increases, the man-hours required for development can be reduced.
Unfortunately refactoring is not a silver bullet.
If you don't make any changes to your existing code, refactoring will have little effect and only the risk will remain. There is no economic rationality there, it is just self-satisfaction.
If you're developing an API and you don't know who is using it, you can't change it.
By its very nature, refactoring does not increase the functionality of the system. If your boss doesn't understand the importance of refactoring, try your best to persuade him. If you can't convince yourself, give up gracefully so that you are not responsible. ~~ (And behind the scenes, let's silently refactor as a software professional.) ~~ It may be avoided when delivery times are tight or when all changes need to be manually tested.
Refactoring can range from small changes like renaming local variables to major changes like replacing switch statements with class polymorphism. If the code you're refactoring is protected by tests, you can refactor with confidence, but legacy code doesn't have tests, so you can't refactor with confidence. However, as far as the refactoring tools provided in the integrated development environment such as Eclipse are concerned, they have been executed (tested) thousands of times worldwide, so refactoring can be done relatively safely even in an environment without automatic testing. I will. ⚠️ Not 100% safe.
Version: 2019-06 (4.12.0) Build id: 20190614-1200
Select the part you want to refactor and right-click → You can execute it from the refactoring menu.
In the case of a shortcut, it is ʻAlt +
Ctrl+
T. (On Mac, ʻAlt
+ ⌘
+ T
)
Refactoring can affect multiple classes and can't be returned with ctrl + z
after several runs.
Make frequent backups so that you can undo your changes.
IDE refactoring is basically safe, but run automated tests as often as possible to make sure that the refactoring doesn't change your behavior.
Java has a powerful mechanism called reflection, but it does not benefit from compiler type checking. Even the refactoring tool of the IDE will not be applicable, so if you are using it in your code, you will not be able to detect that you have broken the code until you execute it. If you are using it in the program, thoroughly investigate the extent of the impact. If you're developing a framework or plugin, you may be using reflection. ~~ Are you using it to break access modifiers in your test code? Who did that? ~~
Finally the main subject. Based on my own judgment and prejudice, I arranged the ones that I use most often and the ones that I think I can use.
** Applicable **
Packages, classes, methods, variables
efficacy
Rename.
You can change variable names, method names, and class names, such as "Why did you use that abbreviation?"
** Optional (when applied to method) **
Keep original method as delegation to renamed method + mark as deprecated
It is also possible to change the method that is open to the outside while keeping the original method to maintain compatibility.
If you select the mark as deprecated, @deprecated
will be added.
before
String getCpyNm() {
return cpyNm;
}
after
String getCompanyName() {
return companyName;
}
after+option
/**
* @deprecated {@link #getCompanyName()}Substitute for
*/
public String getCpyNm() {
return getCompanyName();
}
public String getCompanyName() {
return companyName;
}
** Optional (when applied to class) **
The following options are available.
--Updated variables and methods with similar names --Updated text occurrences in comments and strings --Update fully qualified names in non-Java text files
It is not safe to change the comment or similar method name instead of the referenced part, so it is necessary to check it in the preview.
** Applicable ** Selected line in method efficacy Separate the selected part as a separate method. If there are duplicates in the code, it is possible to replace multiple duplicates at once.
before
public void printAverage(int a, int b, int c) {
int sum = a + b+c;
int average = sum/3;
System.out.println(average);
}
after
public void printAverage(int a, int b, int c) {
int average = getAverage(a, b, c);
System.out.println(average);
}
private int getAverage(int a, int b, int c) {
int sum = a + b+c;
int average = sum/3;
return average;
}
** Applicable ** The selected formula or conditional expression in the method efficacy Divide long expressions, etc., or introduce explanatory variables Reverse of inline
before
public int getTotal(int price) {
int result = (int) (price * 0.8 * 1.10);
return result;
}
after
public int getTotal(int price) {
double discountPrice = price * 0.8;
int result = (int) (discountPrice * 1.10);
return result;
}
** Applicable ** variable efficacy Replace redundant variable declarations with their values The reverse of local variable extraction
before
public int getTotal(int price) {
double discountPrice = price * 0.8;
int result = (int) (discountPrice * 1.10);
return result;
}
after
public int getTotal(int price) {
int result = (int) ((price * 0.8) * 1.10);
return result;
}
** Applicable ** constant efficacy Change the constant to a member variable. Only static values can be used.
before
public int getTotal(int price) {
int result = (int) (price * 0.8 * 1.10);
return result;
}
after
public static final double TAX_RATE = 1.10;
public int getTotal(int price) {
int result = (int) (price * 0.8 * TAX_RATE);
return result;
}
** Applicable **
Member variables
efficacy
Generate a member variable getter / setter and replace the reference method with one that uses getter / setter.
option
If you set declarative field access
to hold field reference
, you can keep the value of the field directly referenced.
before
public class Refactoring {
private String companyName = "";
private int companyId = 0;
public Refactoring(String companyName, int companyId) {
this.companyName = companyName;
this.companyId = companyId;
}
}
after
public class Refactoring {
private String companyName = "";
private int companyId = 0;
public Refactoring(String companyName, int companyId) {
this.companyName = companyName;
this.setCompanyId(companyId);
}
/**
* @return companyId
*/
private int getCompanyId() {
return companyId;
}
/**
* @param companyId set companyId
*/
private void setCompanyId(int companyId) {
this.companyId = companyId;
}
}
** Applicable ** Local variables efficacy Change local variables to member variables. Similar to constant extraction option Field access modifiers and initialization positions can be changed
before
public class Refactoring {
public int getTotal(int price) {
double discountRate = 0.8;
int result = (int) (price * discountRate * 1.10);
return result;
}
}
after
public class Refactoring {
private double discountRate = 0.8;
public int getTotal(int price) {
int result = (int) (price * discountRate * 1.10);
return result;
}
}
** Applicable ** Package, class efficacy Move the class to another package, move / rename the package. If you move a package, you can change the subpackages at once.
package com.example.refactoring;
package com.example.refactoring.util;
** Applicable ** static variables, static methods efficacy You can move static variables and static methods to another class. It can also be used for member variables, but since it cannot hold a reference, there is a high probability that a compile error will occur. .. .. (Is it refactoring?)
before
public class Refactoring {
public static final String staticString = "s";
public static String getStaticString() {
return staticString;
}
}
public class OtherClass {
}
after
public class Refactoring {
public static String getStaticString() {
return OtherClass.staticString;
}
}
public class OtherClass {
public static final String staticString = "s";
}
** Applicable **
Method
efficacy
Add, remove, and change method arguments
Troublesome sorting is also possible with copy
option
If you check Keep original method as delegation to changed method
, you can keep the method of original signature.
before
public Refactoring(String companyName) {
this.companyName = companyName;
}
after
public Refactoring(String companyName, String newParam) {
this.companyName = companyName;
}
after(Keep the original method as a delegation to the modified method)
/**
* @deprecated {@link #Refactoring(String,String)}Substitute for
*/
public Refactoring(String companyName) {
this(companyName, null);
}
public Refactoring(String companyName, String newParam) {
this.companyName = companyName;
}
** Applicable **
class
efficacy
Create an interface from an existing class.
You can create an interface by selecting any public method of an existing class, the created interface is automatically specified in ʻimplements, and the method is annotated with
@Override`.
before
public class Refactoring {
private String companyName = "";
public String getCompanyName() {
return companyName;
}
}
after
public interface RefactoringInterface {
String getCompanyName();
}
public class Refactoring implements RefactoringInterface {
private String companyName = "";
@Override
public String getCompanyName() {
return companyName;
}
}
** Applicable ** Class (substantial member variable) efficacy Group member variables into a separate class. It is used when the class becomes bloated or when related things such as IP address and port number are put together. Methods cannot be extracted using only member variables. option The extraction destination can be selected from top-level class and anonymous class. In the case of top level class, it is extracted as another class and In the case of anonymous class, the class is extracted in the same class.
before
public class Refactoring {
private String companyName = "";
private String postNo = "";
public void main() {}
}
after(For top level class)
public class Refactoring {
private RefactoringData data = new RefactoringData("", "");
public void main() {}
}
public class RefactoringData {
public String companyName;
public String postNo;
public RefactoringData(String companyName, String postNo) {
this.companyName = companyName;
this.postNo = postNo;
}
}
after(For anonymous classes)
public class Refactoring {
public static class RefactoringData {
public String companyName;
public String postNo;
public RefactoringData(String companyName, String postNo) {
this.companyName = companyName;
this.postNo = postNo;
}
}
private RefactoringData data = new RefactoringData("", "");
public void main() {}
}
** Applicable **
Method
efficacy
Combine arbitrary arguments into one object
option
If you check Keep original method as delegation to changed method
, you can keep the method of original signature.
You can select the parameter object to generate from either the top level class
or the anonymous class
.
before
public class Refactoring {
public Refactoring(String companyName, int companyId) {
this.companyName = companyName;
this.companyId = companyId;
}
}
after(Specify top level class)
public class Refactoring {
public Refactoring(RefactoringParameter parameterObject) {
this.companyName = parameterObject.companyName;
this.companyId = parameterObject.companyId;
}
}
public class RefactoringParameter {
public String companyName;
public int companyId;
public RefactoringParameter(String companyName, int companyId) {
this.companyName = companyName;
this.companyId = companyId;
}
}
after(Specify anonymous class)
public class Refactoring {
/**
* @deprecated {@link #Refactoring(RefactoringParameter)}Substitute for
*/
public Refactoring(String companyName, int companyId) {
this(new RefactoringParameter(companyName, companyId));
}
public Refactoring(RefactoringParameter parameterObject) {
this.companyName = parameterObject.companyName;
this.companyId = parameterObject.companyId;
}
}
public class RefactoringParameter {
//Parameter object is the same
}
** Applicable ** Variables and constants in the method efficacy Change variables and constants in the method to method arguments
before
public String getCompanyName() {
return "prefix_" + companyName;
}
after
public String getCompanyName(String prefix) {
return prefix + companyName;
}
** Applicable ** class efficacy Create a superclass from an existing class. A superclass can be created by specifying arbitrary member variables and methods from an existing class, and ʻextends` is automatically specified.
before
public class Refactoring {
private String companyName = "";
public String getCompanyName() {
return companyName;
}
}
after
public class RefactoringSuper {
private String companyName = "";
public String getCompanyName() {
return companyName;
}
}
public class Refactoring extends RefactoringSuper {
}
** Applicable **
Superclass / subclass member variables and methods
efficacy
Move member variables and methods between superclasses / subclasses
Pull-up moves from subclass to superclass,
Pushdown moves from superclass to subclass.
** Optional (during pushdown) **
If you select Leave abstract declaration
, you can leave the method moved to the superclass as abstruct.
After pull-up
public class SuperClass {
private String companyName = "";
public String getCompanyName() {
return companyName;
}
}
public class Refactoring extends SuperClass {
}
After pushdown
public class SuperClass {
}
public class Refactoring extends SuperClass {
private String companyName = "";
public String getCompanyName() {
return companyName;
}
}
After pushdown+Leave an abstract declaration
public abstract class SuperClass {
public abstract String getCompanyName();
}
public class Refactoring extends SuperClass {
private String companyName = "";
public String getCompanyName() {
return companyName;
}
}
** Applicable ** constructor efficacy Replace the constructor with a static factory method. It is used when you want to make the target class a singleton class or when you want to flexibly change the generation method.
before
public class Refactoring {
private String companyName = "";
public Refactoring(String companyName) {
this.companyName = companyName;
}
}
after
public class Refactoring {
public static Refactoring createRefactoring(String companyName) {
return new Refactoring(companyName);
}
private String companyName = "";
private Refactoring(String companyName) {
this.companyName = companyName;
}
}
** Applicable ** Class (reference within practically other methods) efficacy If a superclass can be used as a substitute, replace it with a superclass. In the example below, the Declaration of the Use class has been replaced, but it is the SubClass that performs the refactoring.
Class definition
public class SuperClass {
protected String companyName = "";
public String getCompanyName() {
return companyName;
}
}
public class Refactoring extends SuperClass {
}
before
public class Use {
public void main() {
Refactoring instance = new Refactoring("", 0);
System.out.println(instance.getCompanyName());
}
}
after
public class Use {
public void main() {
SuperClass instance = new Refactoring("", 0);
System.out.println(instance.getCompanyName());
}
}
** Applicable ** Anonymous class (inner class) efficacy Move anonymous class to another file
before
public class Refactoring {
private String companyName = "";
private int companyId = 0;
public static class RefactoringParameter {
public String companyName;
public int companyId;
public RefactoringParameter(String companyName, int companyId) {
this.companyName = companyName;
this.companyId = companyId;
}
}
public Refactoring(RefactoringParameter parameterObject) {
this.companyName = parameterObject.companyName;
this.companyId = parameterObject.companyId;
}
}
after
public class Refactoring {
private String companyName = "";
private int companyId = 0;
public Refactoring(RefactoringParameter parameterObject) {
this.companyName = parameterObject.companyName;
this.companyId = parameterObject.companyId;
}
}
public class RefactoringParameter {
public String companyName;
public int companyId;
public RefactoringParameter(String companyName, int companyId) {
this.companyName = companyName;
this.companyId = companyId;
}
}
** Applicable ** Member variable type, method return type, variable type efficacy Replace the type with a superclass type. It can be changed to a superclass like String type → Object type. However, it cannot be changed if it is referenced as a String type in another class and is not compatible.
before
public String getCompanyName() {
return companyName;
}
after
public Object getCompanyName() {
return companyName;
}
There were a lot of features that I learned for the first time about refactoring in Eclipse. The number of: star: is small for those that I personally didn't know how to use. Please let me know if there is a convenient use. It's not 100% safe, but it's overwhelmingly faster and safer than the method of manually fixing the part where the error occurred after changing it, so let's refactor it steadily.