- PVSM.RU - https://www.pvsm.ru -
Эту статью можно рассматривать как краткий обзор c gif-ками по рефакторингам Java-файлов в IDEA для начинающих.
Осторожно, много тяжелых gif-картинок.
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” —M. Fowler (1999)
Введение [1]
Раздел «Refaсtor» [2] [3]
- Refactor This [3] [4]
- Rename [4] [5]
- Rename File [5] [6]
- Change Signature [6] [7]
- Edit Property Value (без примера) [7] [8]
- Type Migration [8] [9]
- Make Static [9] [10]
- Convert To Instance Method [10] [11]
- Move Classes [11] [12]
- Copy Classes [12] [13]
- Safe Delete [13] [14]
- Extract/Introduce [14] [15]
- - Variable [15] [16]
- - Constant [16] [17]
- - Field [17] [18]
- - Parameter [18] [19]
- - Functional Parameter [19] [20]
- - Functional Variable [20] [21]
- - Parameter Object [21] [22]
- - Method [22] [23]
- - Type Parameter (без примера) [23] [24]
- - Interface [24] [25]
- - Superclass [25] [26]
- - Subquery as CTE (без примера) [26] [27]
- - RSpec 'let' (без примера) [27] [28]
- Inline [28] [29]
- Find and Replace Code Duplicate [29] [30]
- Pull Member Up [30] [31]
- Pull Member Down [31] [32]
- Push ITds In [32] [33]
- Use Interface Where Possible [33] [34]
- Replace Inheritance with Delegation [34] [35]
- Remove Middleman [35] [36]
- Wrap Method Return Value [36] [37]
- Encapsulate Field [37] [38]
- Replace Temp with Query [38] [39]
- Replace Constructor with Factory Method [39] [40]
- Replace Constructor with Builder [40] [41]
- Generify [41] [42]
- Migrate [42] [43]
- Lombok и Delombok (без примера) [43] [44]
- Internationalize [44] Список источников [45]
Цель данной статьи - показать доступные способы рефакторинга для Java-файлов (многие способы будут работать и для других языков). Как использовать эти приемы в реальной жизни показано в замечательном видео Тагира Валеева (ссылка в списке источников [45]).
Думаю, каждый, кто работает в IDEA, знает, что в ней куча способов для рефакторинга кода. И почти уверен, что каждый второй смотрит анонсы новой версии, где красиво показаны новые способы рефакторинга и заглядывал в раздел Refaсtor:
Но не уверен, что все точно знают что и как делают все элементы этого списка, хотя они все детально описаны в справки к idea [46]
В статье представлены фрагменты кода, порядок действий и анимации почти для каждого пункта. Также постарался добавить, где возможно, ссылку на замечательную книгу Refactoring: Improving the Design of Existing Code (Martin Fowler) [47]. Чтобы не сильно раздувать трафик пришлось довольно сильно обрезать много gif-картинок, поэтому обязательно смотрите использованный код под катом. Горячие клавиши приведены для Windows/LInux по умолчанию.
Пойдем сверху вниз по порядку.
Данный пункт используется для быстрого доступа к списку доступных способов рефакторинга. Заметьте, список зависит от места, где вы его вызываете. Здесь и далее в коде указывает на место каретки в коде, при вызове.
Позволяет переименовать практически любой идентификатор в коде, будь то переменная или названия класса. Изменения распространяются по всему проекту, в некоторых случаях, включая и комментарии. (У Фаулера переименованию посвящено 2 главы - “Rename Field” и “Rename Variable”)
До
public class Main {
public static void main(String[] args) {
System.out.print("Hello");
invo<caret/>ke(", World");
}
private static void invoke(String text) {
//text
System.out.println(text);
}
}
После
public class Main {
public static void main(String[] args) {
System.out.print("Hello");
newFunctionName(", World");
}
private static void newFunctionName(String text) {
//text
System.out.println(text);
}
}
Переименование переменной
До
public class Main {
public static void main(String[] args) {
System.out.print("Hello");
invoke(", World");
}
private static void invoke(String te<caret>xt) {
//text
System.out.println(text);
}
}
После
public class Main {
public static void main(String[] args) {
System.out.print("Hello");
invoke(", World");
}
private static void invoke(String newText) {
//newText
System.out.println(newText);
}
}
Переименование вложенного класса
До
public class Main {
public static void main(String[] args) {
System.out.print("Hello");
invoke(", World");
}
private static void invoke(String text) {
//text
System.out.println(text);
throw new MyExc<caret>eption();
}
public static class MyException extends RuntimeException {
}
}
После
public class Main {
public static void main(String[] args) {
System.out.print("Hello");
invoke(", World");
}
private static void invoke(String text) {
//text
System.out.println(text);
throw new NewMyException ();
}
public static class NewMyException extends RuntimeException {
}
}
Переименование класса
До
public class Main {
public static void main(String[] args) {
MyS<caret>ervice service = new MyService();
service.service();
}
}
После
public class Main {
public static void main(String[] args) {
NewMyService myService = new NewMyService ();
myService.service();
}
}
Переименование пакета
package gen<caret>eral;
public class Main {
public static void main(String[] args) {
NewMyService service = new NewMyService();
service.service();
}
}
После
package org.test.java.src;
public class Main {
public static void main(String[] args) {
NewMyService service = new NewMyService();
service.service();
}
}
Переименовывает файл и ссылки на этот файл. В принципе можно вызывать через Shift+F6 если выделен файл. В диалоговом окне можно указать область поиска для переименований (Scope), искать ли ссылки или в комментариях и строчках
До
public class Main {
public static void main(String[] args) throws IOException {
Path path = Paths.get("src/general/TestFile.txt");
String read = Files.readAllLines(path).get(0);
System.out.println(read);
}
}
После
public class Main {
public static void main(String[] args) throws IOException {
Path path = Paths.get("src/general/TestFile2.txt");
String read = Files.readAllLines(path).get(0);
System.out.println(read);
}
}
У Фаулера этому посвящена глава “Change Function Declaration”. В новой версии IDEA «Change Signature» был немного доработан. Я знаю два пути:
первый путь - прямой - изменить сигнатуру метода и вызвать обновление,
второй - через диалоговое окно.
Пример для первого способа (через изменения сигнатуры метода)
Изменяем сигнатуру метода. В этот момент слева появляется "R" и в контекстном меню появляется пункт "Update usages to reflect signature change", который позволяет обновить все использования метода.
До
public class ChangeSignature {
public static void main(String[] args) {
invokeMethod("Hello");
invokeMethod("World");
}
private static void invokeMethod(String text) {
System.out.println(text);
}
}
После
public class ChangeSignature {
public static void main(String[] args) {
invokeMethod("Hello", null);
invokeMethod("World", null);
}
private static void invokeMethod(String text, String newType) {
System.out.println(text);
}
}
Пример для второго способа (через диалоговое окно)
В диалоговом окне можно изменить состав переменных, exception, и даже сгенерировать переопределенный метод.
До
public class ChangeSignature {
public static void main(String[] args) {
invokeMethod("Hello");
invokeMethod("World");
}
private static void invokeMethod(String<caret> text) {
System.out.println(text);
}
}
После
public class ChangeSignature {
public static void main(String[] args) {
invokeMethod("Hello");
invokeMethod("World");
}
private static void invokeMethod(String text) {
invokeMethod(text, null);
}
private static void invokeMethod(String text, String newName) {
System.out.println(text);
}
}
На данный момент (Idea 2020.2) экспериментальная функция и по умолчанию не включена. Включить можно параметром property.value.inplace.editing=true Поэтому примеры не привожу.
Позволяет изменить тип переменной, включая сигнатуры методов, возвращаемый тип переменной.
До
public class ChangeSignature {
public static void main(String[] args) {
Inte<caret>ger hello = 1;
print(hello);
}
private static void print(Integer text) {
System.out.println(text);
}
}
После
public class ChangeSignature {
public static void main(String[] args) {
Number hello = 1;
print(hello);
}
private static void print(Number text) {
System.out.println(text);
}
}
Позволяет сконвертировать метод или внутренний класс в статический. (Противоположность Convert To Instance Method [10])
До
public class MakeStatic {
public static void main(String[] args) {
MakeStatic makeStatic = new MakeStatic();
makeStatic.sayHello();
}
public void say<caret>Hello() {
System.out.println("Hello, World");
}
}
После
public class MakeStatic {
public static void main(String[] args) {
MakeStatic makeStatic = new MakeStatic();
MakeStatic.sayHello();
}
public static void sayHello() {
System.out.println("Hello, World");
}
}
Позволяет сконвертировать статический метод в нестатический (противоположность ”Make Static” [9]). При этом можно указать к какому классу будет относится новый метод.
До
public class MakeStatic {
public static void main(String[] args) {
sayHello();
}
public static void sa<caret>yHello() {
System.out.println("Hello, World");
}
}
После
public class MakeStatic {
public static void main(String[] args) {
new MakeStatic().sayHello();
}
public void sayHello() {
System.out.println("Hello, World");
}
}
В принципе делает, что и написано, перемещает классы.
До
package org.example.test.service;
public class TestService {
<caret>
}
После
package org.example.test;
public class TestService {
}
Многие программисты любят копировать файлы, а не начинать с чистого листа. Для этого прекрасно подходит F5. Меняем название на нужноe, указываем пакет и готово.
По функциональности почти повторяет то, что можно получить через контекстное меню (Alt + Enter), но позволяет удалять чуть больше. Поэтому, я заметил, у многих знакомых любимый способ рефакторинга - F2(следующая ошибка) и Alt + Enter или Alt + Delete. Можно удалять классы, переменные, методы. Перед удалением IDEA выполнит поиск использования удаляемых элементов, и если IDEA найдет, что они где-то используется покажет диалоговое окно Usages Detected. Про удаление неиспользуемого кода у Фаулера есть целая глава - “Remove Dead Code”
До
package org.example.test;
public class MainClass {
public static void main(String[] args) {
start();
}
private static void start() {
String unUsedVariable;
System.out.println("Hello, World!");
}
private static void unUsedMethod() {
}
}
После
<empty>
Следующий блок - Extract/Introduce. Думаю, является одним из самых популярных. Позволяет извлекать разные части программы.
Создает новую переменную из выделенного фрагмента. (Этому способу у Фаулера посвящена глава “Extract Variable”).
До
public class ExtractVariable {
public static void main(String[] args) {
sayHello();
}
private static void sayHello() {
System.out.println("He<caret>llo, World!");
}
}
После
public class ExtractVariable {
public static void main(String[] args) {
sayHello();
}
private static void sayHello() {
String text = "Hello, World!";
System.out.println(text);
}
}
Создает новую константу из выделенного фрагмента.
До
public class ExtractVariable {
public static void main(String[] args) {
sayHello();
}
private static void sayHello() {
System.out.println("He<caret>llo, World!");
}
}
После
public class ExtractVariable {
public static final String HELLO_WORLD = "Hello, World!";
public static void main(String[] args) {
sayHello();
}
private static void sayHello() {
System.out.println(HELLO_WORLD);
}
}
Создает новое поле класса из выделенного фрагмента.
До
public class ExtractVariable {
public static void main(String[] args) {
sayHello();
}
private static void sayHello() {
System.out.println("He<caret>llo, World!");
}
}
После
public class ExtractVariable {
private static String x;
public static void main(String[] args) {
sayHello();
}
private static void sayHello() {
x = "Hello, World!";
System.out.println(x);
}
}
Создает новый параметр (функции) из выделенного фрагмента.
До
public class ExtractVariable {
public static void main(String[] args) {
sayHello();
}
private static void sayHello() {
System.out.println("He<caret>llo, World!");
}
}
После
public class ExtractVariable {
public static void main(String[] args) {
sayHello("Hello, World!");
}
private static void sayHello(String x) {
System.out.println(x);
}
}
Очень похож на пункт «Parameter» [18], но теперь в функцию мы передаем или java.util.function.Supplier, или javafx.util.Builder. Обратите внимание, данный рефакторинг может привести к нежелательным эффектам [48].
До
public class ExtractParameter {
public static void main(String[] args) {
System.out.println(generateText());
}
private static String generateText() {
return "Hello, Wor<caret>ld!".toUpperCase();
}
}
После
public class ExtractParameter {
public static void main(String[] args) {
System.out.println(generateText(() -> "Hello, World!"));
}
private static String generateText(final Supplier<string> getText) {
return getText.get().toUpperCase();
}
}
Очень похож на пункт «Variable» [18], но теперь мы получаем или java.util.function.Supplier или javafx.util.Builder.
До
public class ExtractParameter {
public static void main(String[] args) {
System.out.println(generateText());
}
private static String generateText() {
return "Hello, W<caret>orld!".toUpperCase();
}
}
После
public class ExtractParameter {
public static void main(String[] args) {
System.out.println(generateText());
}
private static String generateText() {
Supplier<string> getText = () -> "Hello, World!";
return getText.get().toUpperCase();
}
}
Удобный способ, когда в функцию передается много аргументов и вам надо обернуть их в класс. (У Фаулера это глава “Introduce Parameter Object”).
До
public class ExtractParameter {
public static void main(String[] args) {
System.out.println(generateText("Hello", "World!"));
}
private static String generateText(Str<caret>ing hello, String world) {
return hello.toUpperCase() + world.toUpperCase();
}
}
После
public class ExtractParameter {
public static void main(String[] args) {
System.out.println(generateText(new HelloWorld("Hello", "World!")));
}
private static String generateText(HelloWorld helloWorld) {
return helloWorld.getHello().toUpperCase() + helloWorld.getWorld().toUpperCase();
}
private static class HelloWorld {
private final String hello;
private final String world;
private HelloWorld(String hello, String world) {
this.hello = hello;
this.world = world;
}
public String getHello() {
return hello;
}
public String getWorld() {
return world;
}
}
}
Извлекаем метод из выделенного фрагмента. (У Фаулера есть глава про похожий способ рефакторинга - “Extract Function”).
До
public class ExtractMethod {
public static void main(String[] args) {
String text = "Hello, World!";
System.out.prin<caret>tln(text);
}
}
После
public class ExtractMethod {
public static void main(String[] args) {
String text = "Hello, World!";
print(text);
}
private static void print(String text) {
System.out.println(text);
}
}
Рефакторинг из мира Kotlin, и для Java не применим (буду рад добавить, если кто-то сделает пример).
Оборачивает выделенный фрагмент в объект. Может использоваться, если надо вернуть несколько объектов из метода (возвращает объект-обертку).
До
public class ExtractMethod {
public static void main(String[] args) {
String text = "Hello, World!";
print(text);
}
private static void print(String text) {
System.out.p<caret>rintln(text);
}
}
После
public class ExtractMethod {
public static void main(String[] args) {
String text = "Hello, World!";
print(text);
}
private static void print(String text) {
new Printer(text).invoke();
}
private static class Printer {
private String text;
public Printer(String text) {
this.text = text;
}
public void invoke() {
System.out.println(text);
}
}
}
Позволяет извлечь методы и поля в отдельный класс.
До
public class Delegate {
public static void main(String[] args) {
new Delegate().print();
}
private void print() {
System.ou<caret>t.println("Hello, World!");
}
}
После
public class Delegate {
private final Printer printer = new Printer();
public static void main(String[] args) {
new Delegate().print();
}
private void print() {
printer.print();
}
public static class Printer {
public Printer() {
}
private void print() {
System.out.println("Hello, World!");
}
}
}
Для заданного класса и его методов создает интерфейс. (Особенно удобно, когда при работе со Spring, когда кто-то забыл для компонента создать соответствующий интерфейс)
До
public class ExtractImpl {
public static void main(String[] args) {
new ExtractImpl().print();
}
public void print() {
System.out.println("Hello, World!");
}
}
После
public class ExtractImpl implements ExtractInterface {
public static void main(String[] args) {
new ExtractImpl().print();
}
@Override
public void print() {
System.out.println("Hello, World!");
}
}
public interface ExtractInterface {
void print();
}
Аналогично пункту «Interface» [24], только теперь создается класс-родитель (Superclass). Фаулер описывает этот способ рефакторинга в главе “Extract Superclass”.
До
public class ExtractImpl {
public static void main(String[] args) {
new ExtractImpl().print();
}
public void print() {
System.out.println("Hello, World!");
}
}
После
public class ExtractImpl extends ExtractAbstr {
public static void main(String[] args) {
new ExtractImpl().print();
}
}
public class ExtractAbstr {
public void print() {
System.out.println("Hello, World!");
}
}
Относится к Sql, поэтому пропускаю. Если кто-то пришлет пример, хотя бы в виде кода - с удовольствием дополню.
Относится к Ruby, поэтому пропускаю Если кто-то пришлет пример, хотя бы в виде кода - с удовольствием дополню.
Возможно один из самых крутых методов рефакторинга, Инлайнить можно почти все. Фаулер описывает этот способ рефакторинга в главах “Inline Class”, “Inline Function”, “Inline Variable”.
До
public class Inline {
public static void main(String[] args) {
print();
}
private static void print() {
new Printer().print();
}
private static class Printer {
public void print() {
String text = "Hello, World!";
System.out.println(t<caret>ext);
}
}
}
После
public class Inline {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Ищет похожие фрагменты кода и предлагает заменить их, например, вызовом метода или константой.
До
public class Replace {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
public void print() {
System.out.println("Hello, World!");
}
public void print2() {
System.out.prin<caret>tln("Hello, World!");
}
}
После
public class Replace {
public static void main(String[] args) {
print2();
}
public void print() {
print2();
}
public static void print2() {
System.out.println("Hello, World!");
}
}
Позволяет инвертировать булевые переменные.
До
public class Invert {
public static void main(String[] args) {
boolean co<caret>ndition = true;
if (condition) {
System.out.println("Hello, World!");
}
}
}
После
public class Invert {
public static void main(String[] args) {
boolean condition = false;
if (!condition) {
System.out.println("Hello, World!");
}
}
}
Позволяет перемещать методы или поля по иерархии вверх. Зачем это нужно написано у Фаулера в главах “Pull Up Field” и “Pull Up Method”. Выполняет обратную задачу пункта «Pull Member Down» [31].
До
public class PullMethod {
public static void main(String[] args) {
new InnerClass().print();
}
private static class InnerClass extends AbstClass {
public void print() {
System.out.pri<caret>ntln("Hello, World");
}
}
private static abstract class AbstClass {
}
}
После
public class PullMethod {
public static void main(String[] args) {
new InnerClass().print();
}
private static class InnerClass extends AbstClass {
}
private static abstract class AbstClass {
public void print() {
System.out.println("Hello, World");
}
}
}
Выполняет обратную задачу пункта «Pull Member Up» [30]. Позволяет перемещать методы или поля по иерархии вниз. (У Фаулера - глава “Push Down Method”)
До
public class PullMethod {
public static void main(String[] args) {
new InnerClass().print();
}
private static class InnerClass extends AbstClass {
}
private static abstract class AbstClass {
public void print() {
System.out.prin<caret>tln("Hello, World");
}
}
}
После
public class PullMethod {
public static void main(String[] args) {
new InnerClass().print();
}
private static class InnerClass extends AbstClass {
@Override
public void print() {
System.out.println("Hello, World");
}
}
private static abstract class AbstClass {
public abstract void print();
}
}
Используется при работе с AsperctJ.
До
aspect myAspect {
boolean Account.closed = <caret>false;
void Account.close() {
closed = true;
}
}
class Account {
}
После
aspect myAspect {
boolean Account.closed = false;
}
class Account {
void close() {
closed = true;
}
}
IDEA старается заменить, где это возможно, указания классов на указание интерфейсов.
До
public class ExtractInterface {
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
print(innerClass);
}
private static void print(InnerClass innerClass) {
innerClass.print();
}
private static class InnerClass implements InnerInterface{
@Override
public void print() {
System.out.println("Hello, World!");
}
}
private static interface InnerInterface{
void print();
}
}
После
public class ExtractInterface {
public static void main(String[] args) {
InnerInterface innerClass = new InnerClass();
print(innerClass);
}
private static void print(InnerInterface innerClass) {
innerClass.print();
}
private static class InnerClass implements InnerInterface{
@Override
public void print() {
System.out.println("Hello, World!");
}
}
private static interface InnerInterface{
void print();
}
}
Заменяет наследование делегированием. У Фаулера про это главы “Replace Subclass with Delegate” и “Replace Superclass with Delegate”.
До
public class InheritanceDelegation {
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
print(innerClass);
}
private static void print(InnerClass innerClass) {
innerClass.print();
}
private static class In<caret>nerClass extends AbstractClass {
}
private static class AbstractClass {
public void print() {
System.out.println("Hello, World!");
}
}
}
После
public class InheritanceDelegation {
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
print(innerClass);
}
private static void print(InnerClass innerClass) {
innerClass.print();
}
private static class InnerClass {
private final AbstractClass abstractClass = new AbstractClass();
public void print() {
abstractClass.print();
}
}
private static class AbstractClass {
public void print() {
System.out.println("Hello, World!");
}
}
}
Заменяет все делегированные вызовы на прямые. (У Фаулера - глава “Remove Middle Man”).
До
public class Middleman {
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
innerClass.print();
}
private static class InnerClass {
private final NextClass next<caret>Class = new NextClass();
public void print() {
nextClass.print();
}
}
private static class NextClass {
public void print() {
System.out.println("Hello, World!");
}
}
}
После
public class Middleman {
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
innerClass.getNextClass().print();
}
private static class InnerClass {
private final NextClass nextClass = new NextClass();
public NextClass getNextClass() {
return nextClass;
}
}
private static class NextClass {
public void print() {
System.out.println("Hello, World!");
}
}
}
Оборачивает возвращаемое значение в объект-обертку. Удобно, когда нужно возвращать несколько связанных значений.
До
public class WrapMethodReturnValue {
public static void main(String[] args) {
System.out.println(new MessageFolder().get());
}
private static class MessageFolder {
public String get() {
ret<caret>urn "Hello, World!";
}
}
}
После
public class WrapMethodReturnValue {
public static void main(String[] args) {
System.out.println(new MessageFolder().get().getValue());
}
private static class MessageFolder {
public Message get() {
return new Message("Hello, World!");
}
public class Message {
private final String value;
public Message(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
}
}
Скрывает поле за getter, setter.
До
public class EncapsulateField {
public static void main(String[] args) {
System.out.println(new InnerClass().message);
}
private static class InnerClass {
public String m<caret>essage = "Hello, World!";
}
}
После
public class EncapsulateField {
public static void main(String[] args) {
System.out.println(new InnerClass().getMessage());
}
private static class InnerClass {
private String message = "Hello, World!";
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
}
Пусть у вас есть
int size = getActualSize()
с помощью этого способа рефакторинга вы можете заменить использование size на использование метода getActualSize(). Это приведет к увеличению количества вызовов методов, но в некоторых случаях может оказаться полезным. Пример так же показывает возможность извлечения метода с одновременным его дальнейшим использованием.
До
public class ReplaceTemp {
public static void main(String[] args) {
String hello = "Hello";
String mes<caret>sage = hello + ", World!";
System.out.println(message);
}
}
После
public class ReplaceTemp {
public static void main(String[] args) {
String hello = "Hello";
System.out.println(message(hello));
}
private static String message(String hello) {
return hello + ", World!";
}
}
Генерирует фабричный метод для указанного конструктора. Идеально, если у вас нет Lombok. (У Фаулера этому посвящена глава “Replace Constructor with Factory Function”).
До
public class ReplaceConstructor {
public static void main(String[] args) {
new InnerClass("Hello", "World").print();
}
private static class InnerClass {
private String message;
public Inner<caret>Class(String hello, String world) {
message = hello + ", " + world;
}
public void print() {
System.out.println(message);
}
}
}
После
public class ReplaceConstructor {
public static void main(String[] args) {
InnerClass.createInnerClass("Hello", "World").print();
}
private static class InnerClass {
private String message;
private InnerClass(String hello, String world) {
message = hello + ", " + world;
}
public static InnerClass createInnerClass(String hello, String world) {
return new InnerClass(hello, world);
}
public void print() {
System.out.println(message);
}
}
}
Генерирует builder для указанного конструктора. Идеально, если у вас нет Lombok.
До
public class ReplaceConstructor {
public static void main(String[] args) {
new InnerClass("Hello", "World").print();
}
private static class InnerClass {
private String message;
public InnerC<caret>lass(String hello, String world) {
message = hello + ", " + world;
}
public void print() {
System.out.println(message);
}
}
}
После
public class ReplaceConstructor {
public static void main(String[] args) {
new InnerClassBuilder().setHello("Hello").setWorld("World").createInnerClass().print();
}
static class InnerClass {
private String message;
public InnerClass(String hello, String world) {
message = hello + ", " + world;
}
public void print() {
System.out.println(message);
}
}
}
public class InnerClassBuilder {
private String hello;
private String world;
public InnerClassBuilder setHello(String hello) {
this.hello = hello;
return this;
}
public InnerClassBuilder setWorld(String world) {
this.world = world;
return this;
}
public ReplaceConstructor.InnerClass createInnerClass() {
return new ReplaceConstructor.InnerClass(hello, world);
}
}
Пытается код с raw-типами превратить в код с Generic-типами. Актуален при миграции с java версий ранее 1.5 на современные версии.
До
public class Generify {
public static void main(String[] args) {
List list = getList();
Object message = list.get(0);
System.out.println(message);
}
private static List getList() {
ArrayList arrayList = new ArrayList();
arrayList.add("Hello, World!");
return arrayList;
}
}
После
public class Generify {
public static void main(String[] args) {
List<string> list = getList();
String message = list.get(0);
System.out.println(message);
}
private static List<string> getList() {
ArrayList<string> arrayList = new ArrayList<>();
arrayList.add("Hello, World!");
return arrayList;
}
}
Предоставляет готовые миграции для следующего списка:
А также предоставляет возможность делать свои. Вот, например, правила миграции для JUnit(4.x -> 5.0):
Вот здесь [49] есть подробное видео про миграцию для JUnit(4.x -> 5.0).
Предоставляются плагином “Lombok”. Недавно было объявлено, что теперь он будет входить в стандартную поставку IDEA. Используется при работе с библиотекой кодогенерации “Lombok”.
Используется для интернационализации. К сожалению, в справке не нашел на данный момент информации. IDEA сейчас активно локализуется на другие языки, скорее всего для этого был разработан этот метод.
Прекрасный доклад [50] про атомарный рефакторинг от Тагира Валеева
Справка IDEA [46]
Refactoring: Improving the Design of Existing Code (Martin Fowler) [47]
Автор: pyltsinm
Источник [51]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/359256
Ссылки в тексте:
[1] Введение: #introduction
[2] Раздел «Refaсtor»: #Refaсtor
[3] : #Refactor-This
[4] : #Rename
[5] : #RenameFile
[6] : #ChangeSignature
[7] : #EditPropertyValue
[8] : #TypeMigration
[9] : #MakeStatic
[10] : #ConvertToInstanceMethod
[11] : #MoveClasses
[12] : #CopyClasses
[13] : #Safedelete
[14] : #ExtractIntroduce
[15] : #Variable
[16] : #Constant
[17] : #Field
[18] : #Parameter
[19] : #FunctionalParameter
[20] : #FunctionalVariable
[21] : #ParameterObject
[22] : #Method
[23] : #TypeParameter
[24] : #Interface
[25] : #Superclass
[26] : #SubqueryasCTE
[27] : #RSpeclet
[28] : #Inline
[29] : #FindandReplacecodeduplicate
[30] : #PullMemberUp
[31] : #PullMemberDown
[32] : #PushITdsIn
[33] : #UseInterfaceWherePossible
[34] : #ReplaceInheritancewithdelegation
[35] : #RemoveMiddleman
[36] : #WrapMethodReturnValue
[37] : #EncapsulateField
[38] : #ReplacetempwithQuery
[39] : #ReplaceConstructorwithFactoryMethod
[40] : #ReplaceConstructorwithBuilder
[41] : #Generify
[42] : #Migrate
[43] : #Lombok
[44] : #Internationalize
[45] Список источников: #NOTES
[46] справки к idea: https://www.jetbrains.com/help/idea/refactoring-source-code.html
[47] Refactoring: Improving the Design of Existing Code (Martin Fowler): https://martinfowler.com/books/refactoring.html
[48] нежелательным эффектам: https://www.jetbrains.com/help/idea/extract-parameter.html#side_effects
[49] здесь: https://www.youtube.com/watch?v=F8UTTTDtbH0
[50] Прекрасный доклад: https://2019.jpoint.ru/talks/4ltyzdxqzmpeofbgkld7ns/
[51] Источник: https://habr.com/ru/post/530360/?utm_source=habrahabr&utm_medium=rss&utm_campaign=530360
Нажмите здесь для печати.