137 lines
9.7 KiB
Markdown
137 lines
9.7 KiB
Markdown
|
---
|
|||
|
aliases:
|
|||
|
tags:
|
|||
|
- maturity/🌱
|
|||
|
- type/opinion
|
|||
|
date:
|
|||
|
- - 2024-09-06
|
|||
|
zero-link:
|
|||
|
- "[[../garden/ru/meta/zero/00 Java разработка|00 Java разработка]]"
|
|||
|
parents:
|
|||
|
linked:
|
|||
|
---
|
|||
|
Разработчики Java используют подстановочный знак (`*`) в операторах `import` для добавления всех классов из определенного пакета. Но в ходе ревью большинство из вас, возможно, просили убрать этот подстановочный знак импорта и добавить полное имя класса. Разберемся почему не стоит использовать знак подстановки?
|
|||
|
|
|||
|
Но прежде, давайте вспомним, что полное имя класса, помимо названия, содержит также пакет, например: `java.util.List`. ==Такая запись позволяет нам иметь классы с одинаковыми именами, которые находятся в разных пакетах.==
|
|||
|
|
|||
|
```java
|
|||
|
package com.example;
|
|||
|
|
|||
|
public class WithoutImport {
|
|||
|
|
|||
|
public static void main(String[] args) {
|
|||
|
|
|||
|
java.util.List myList = new java.util.ArrayList();
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
Однако, полная запись весьма непрактична, поэтому в Java существует оператор импорта – `import`. Операторы импорта объявляют компилятору источник имен классов, статических переменных и статических имен методов, используемых в коде. Один раз написали полное имя класса, а дальше используем только название класса.
|
|||
|
|
|||
|
```java
|
|||
|
package com.example;
|
|||
|
|
|||
|
import java.util.ArrayList;
|
|||
|
import java.util.List;
|
|||
|
|
|||
|
public class WithImport {
|
|||
|
|
|||
|
public static void main(String[] args) {
|
|||
|
|
|||
|
List myList = new ArrayList();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
Если мы скомпилируем и запустим эти примеры, результат будет одинаковым.
|
|||
|
|
|||
|
Импорт с подстановочными знаками указывает компилятору искать имена классов в данном пакете. Следовательно, при использовании импорта с wildcard производительность во время компиляции может немного снизиться. Но в большинстве случаев это не окажет заметного влияния.
|
|||
|
|
|||
|
Во время выполнения проблемы с производительностью нет, потому что операторы импорта являются директивами компилятора, и мы не можем найти их в байт-коде. Чтобы пояснить это, мы напишем приведенный выше пример с импортом с подстановочными знаками.
|
|||
|
|
|||
|
```java
|
|||
|
package com.example;
|
|||
|
|
|||
|
import java.util.*;
|
|||
|
|
|||
|
public class WithWildCard {
|
|||
|
public static void main(String[] args) {
|
|||
|
|
|||
|
List myList = new ArrayList();
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
Если мы получим байт-код этого класса, то он будет выглядеть следующим образом
|
|||
|
|
|||
|
```bytecode
|
|||
|
Compiled from "WithWildCard.java"
|
|||
|
public class com.example.WithWildCard {
|
|||
|
public com.example.WithWildCard();
|
|||
|
Code:
|
|||
|
0: aload_0
|
|||
|
1: invokespecial #1 // Method java/lang/Object."<init>":()V
|
|||
|
4: return
|
|||
|
|
|||
|
public static void main(java.lang.String[]);
|
|||
|
Code:
|
|||
|
0: new #2 // class java/util/ArrayList
|
|||
|
3: dup
|
|||
|
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
|
|||
|
7: astore_1
|
|||
|
8: return
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
Если сравнить его с байт-кодом прошлого примера, то они оба имеют одинаковый байт-код.
|
|||
|
|
|||
|
Во время выполнения Java использует байт-код, а не исходный код. ==В байт-коде нет операторов импорта.== Из этого ясно следует, что использование импорта с подстановочными знаками не влияет на производительность Java-приложения во время выполнения.
|
|||
|
|
|||
|
## Недостатки
|
|||
|
Так если использование подстановочного знака не приводит к проблемам производительности, то почему бы его не использовать?
|
|||
|
|
|||
|
### Конфликты имен
|
|||
|
Самая серьезная проблема это возможные конфликты именования. Представьте, что у нас есть два класса из разных библиотек `org.test.Parser` и `dev.lib.Parser`. В нашем коде мы используем импорт с wildcard:
|
|||
|
|
|||
|
```java
|
|||
|
import org.test.*
|
|||
|
import dev.lib.*
|
|||
|
```
|
|||
|
|
|||
|
Компилятор никак не отреагирует на наличие классов с одинаковыми именами в двух разных пакетах, импортируемых таким образом, если только не будет предпринята попытка воспользоваться одним из этих классов.
|
|||
|
|
|||
|
Также проблема может возникнуть в будущем, когда вы обновите версию какую-то из библиотек. Допустим у нас была библиотека с классом `org.test.Parser`, а потом разработчик второй библиотеки тоже добавил класс `dev.lib.Parser`, таким образом мы получили конфлик именования в будущем, хотя раньше все было нормально.
|
|||
|
### Чистый код
|
|||
|
Импорты с подстановочными знаками помогают нам избежать длинного списка импортов. Следовательно, это влияет на читабельность кода, так как читателю может потребоваться прокрутить много страниц в каждом файле исходного кода, прежде чем он доберется до кода, который показывает логику. Несомненно, более читабельный код - это также чистый код.
|
|||
|
|
|||
|
Эта идея также поддерживается в книге "Чистый код" Роберта К. Мартина. Фактически, книга рекомендует использовать импорты с подстановочными знаками при использовании нескольких классов из одного источника. Другими словами, когда мы импортируем два или более классов, импортированных из пакета, лучше импортировать весь пакет.
|
|||
|
|
|||
|
Однако, я не считаю это какой-то проблемой, так как IntelliJ IDEA автоматически скрывает все строки импортов.
|
|||
|
|
|||
|
![](../../meta/files/images/Pasted%20image%2020240906164456.png)
|
|||
|
|
|||
|
Также читаемость ухудшается, потому что разработчик не получает четкого представления о полном пути классов, используемых в коде.
|
|||
|
|
|||
|
Однако, это тоже не является проблемой. Достаточно удерживая Ctrl (cmd) навести курсор на класс и вы увидите пакет, в котором этот класс размещается.
|
|||
|
|
|||
|
![](../../meta/files/images/Pasted%20image%2020240906164524.png)
|
|||
|
|
|||
|
Таким образом проблемы "чистого кода" более не актуальны.
|
|||
|
|
|||
|
## Настройки в Idea
|
|||
|
Intellij Idea автоматически сворачивает импорты, когда полные импорты из какого-то пакета достигают заданного количества. Эта опция настраивается в раделе Preferences > Editor > Code Style > Java во вкладке imports.
|
|||
|
|
|||
|
![](../../meta/files/images/Pasted%20image%2020240906164551.png)
|
|||
|
|
|||
|
Чтобы отключить автоматическое сворачивание импортов достаточно указать число 999. Вот и все, теперь Idea не будет автоматически сворачивать импорты.
|
|||
|
|
|||
|
## Резюмирую
|
|||
|
Использование подстановочных импортов никак не повлияет на производительность программы во время выполнения, но может немного повлиять на производительность во время компиляции.
|
|||
|
|
|||
|
Также при обновлении библиотек вы можете столкнуться с проблемой конфликта имен. Шанс этой проблемы не велик, но и не нулевой.
|
|||
|
|
|||
|
Что касается "чистого кода", то с использованием современных IDE эта проблема не является актуальной.
|