digital-garden/dev/java/Использование wildcard imports в Java.md
Struchkov Mark 65abba8ae6
All checks were successful
continuous-integration/drone/push Build is passing
Новые статьи
2024-09-06 17:05:53 +03:00

137 lines
9.7 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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 эта проблема не является актуальной.