How-To's Tips & Tricks

Basic Refactorings in Action

As you know, two of the most popular basic refactorings that IntelliJ IDEA offers are Extract Method and Inline Method.
The first makes the method shorter and more readable, while the other minimizes the number of unneeded methods, and makes the code more straightforward.
In IntelliJ IDEA you can use both these actions in a row to achieve a more complex result – we call this process multistep refactoring.

Let’s check it out and see what we can do to achieve more with less.

Problem

Let’s say we have a method that checks only one condition:

class CarMechanic {

  void repair(Vehicle vehicle) {
    if (vehicle instanceof Car) {
      System.out.println("Repairing: " + vehicle);
    } else {
      System.out.println("Cannot repair this: " + vehicle);
    }
  }

  void repairWheel(Vehicle vehicle) {
    if (vehicle instanceof Car) {
      System.out.println("Repairing wheel: " + vehicle);
    } else {
      System.out.println("Cannot repair this:" + vehicle);
    }

  }
}

The "Repairing:" branch will be executed only if a Car object is passed to the repair method().
In other cases, the other branch will be executed.

So, if we have an object of Truck type, for example, we will see the output that comes from the else branch.
This might not be exactly the result that we want. The existing check is very coarse and only allows our method to repair Car.
What if we also want to repair another vehicle, such as Truck, in the event that it only has a minor problem such as a flat tire?
Let’s say we already have a method for checking this condition:

class RepairUtils {
  static boolean checkClient(Vehicle vehicle) {
    return (vehicle instanceof Car || vehicle.failureCondition == Vehicle.FailureCondition.FLAT_TIRE);
  }
}

How would we replace our existing checks with calls to this method?

Solution

With the Extract Method refactoring, we will extract the vehicle instanceof Car into a “temporary method”. We will change the method body return vehicle instanceof Car to return RepairUtils.checkClient(vehicle), and then we’ll Inline our method to change the code and yield the following outcome, which will solve our problem with the Truck object:

class CarMechanic {

  void repair(Vehicle vehicle) {
    if (RepairUtils.checkClient(vehicle)) {
      System.out.println("Repairing: " + vehicle);
    } else {
      System.out.println("Cannot repair this: " + vehicle);
    }
  }

  void repairWheel(Vehicle vehicle) {
    if (RepairUtils.checkClient(vehicle)) {
      System.out.println("Repairing wheel: " + vehicle);
    } else {
      System.out.println("Cannot repair this:" + vehicle);
    }

  }
}

Let’s take a look at the refactoring process step by step:

  1. Extract Method

We select our expression vehicle instanceof Car, and press ⌥⌘M for macOs or Ctrl+Alt+M for Windows.

Note that IntelliJ IDEA also displays a notification in the Extract Method dialog if duplicates are found in the code.

After this refactoring, we will have our “temporary” method:

private boolean temp(Vehicle vehicle) {
    return vehicle instanceof Car;
  }
  1. Change Method Body

Now, we will change the method body return vehicle instanceof Car to return RepairUtils.checkClient(vehicle).

  1. Inline Method

Let’s select the name of our extracted method temp and press ⌥⌘N for macOs or Ctrl+Alt+N for Windows.

Notice that the Inline all and remove the method option is selected in the Inline Method dialog.
IntelliJ IDEA removes our “temporary” method and changes the condition to our original method:

class CarMechanic {

  void repair(Vehicle vehicle) {
    if (RepairUtils.checkClient(vehicle)) {
      System.out.println("Repairing: " + vehicle);
    } else {
      System.out.println("Cannot repair this: " + vehicle);
    }
  }

  void repairWheel(Vehicle vehicle) {
    if (RepairUtils.checkClient(vehicle)) {
      System.out.println("Repairing wheel: " + vehicle);
    } else {
      System.out.println("Cannot repair this:" + vehicle);
    }

  }
}

With this example we can see that the combination of the Extract Method and the Inline Method refactorings can solve more complex problems.

We’ve changed the application logic, and now when run the last three lines of the code below shows that our code can process not only Car but also Truck when a minor repair is required, which wasn’t the case before we performed the multistep refactoring.

class RepairShop {
 public static void main(String[] args) {
   CarMechanic cm = new CarMechanic();
   Vehicle v1 = new Car(Vehicle.FailureCondition.ENGINE_FAILURE);
   Vehicle v2 = new Truck(Vehicle.FailureCondition.ENGINE_FAILURE);
   Vehicle v3 = new Truck(Vehicle.FailureCondition.FLAT_TIRE);
   cm.repair(v2);//Repairing: Car, ENGINE_FAILURE
   cm.repair(v2);//Cannot repair this: Truck, ENGINE_FAILURE
   cm.repair(v3);//Repairing: Truck, FLAT_TIRE
 }
}

You don’t always need complex solutions to refactor your code efficiently – sometimes you only need to know the basics.

Happy developing!