[JAVA] Eclipse refactoring summary

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.

What is refactoring?

Refactoring is the process of improving the internal structure of software while preserving its external behavior.

Reasons for refactoring

Improve software design

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.

Make the software easier to understand

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.

Speed up development in the long run

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.

When avoiding refactoring

Unfortunately refactoring is not a silver bullet.

I will continue to salt the cord

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.

Externally exposed interface

If you're developing an API and you don't know who is using it, you can't change it.

I can't persuade my boss

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 in Eclipse

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.

Confirmation environment

Version: 2019-06 (4.12.0) Build id: 20190614-1200

Refactoring method

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)

Precautions when performing refactoring

Make frequent backups

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.

Run frequently, if automated tests exist

IDE refactoring is basically safe, but run automated tests as often as possible to make sure that the refactoring doesn't change your behavior.

If reflection is used, thoroughly investigate the extent of impact

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? ~~

Each refactoring

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.

Rename: star :: star :: star :: star :: star ::

** 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.

Method extraction: star :: star :: star :: star :: star ::

** 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;
}

Extracting local variables: star :: star :: star :: star :: star ::

** 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;
  }

Inline: star :: star :: star :: star :: star ::

** 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;
  }

Extraction of constants: star :: star :: star :: star ::

** 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;
  }

Field Encapsulation: star :: star :: star :: star ::

** 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;
  }

}

Convert local variables to fields: star :: star :: star :: star ::

** 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;
  }
}

Move: star :: star :: star ::

** 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";
}

Method signature changes: star :: star :: star:

** 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;
  }

Interface extraction: star :: star :: star:

** 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;
  }
}

Class extraction: star :: star :: star:

** 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() {}
}

Introducing parameter objects: star :: star :: star:

** 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
}

Parameter introduction: star :: star:

** 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;
  }

Extraction of superclass: star :: star:

** 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 {
}

Pull-up / push-down: star :: star:

** 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;
  }
}

Introducing the factory: star :: star:

** 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;
  }
}

Use supertype when available: star:

** 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());
  }
}

Move type to new file: star:

** 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;
  }
}

Generalization of declared types: star:

** 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;
}

Finally

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.

Recommended Posts

Eclipse refactoring summary
Summary
Eclipse error
ransack summary
Refactoring Ruby
Refactoring Ruby
Eclipse --Springboot