digital-garden/dev/java/Использование wildcard imports в Java.md

148 lines
10 KiB
Markdown
Raw Normal View History

2024-09-06 17:05:53 +03:00
---
aliases:
tags:
- maturity/🌱
- type/opinion
2024-09-08 00:56:18 +03:00
date: 2024-09-06
2024-09-06 17:05:53 +03:00
zero-link:
- "[[../../meta/zero/00 Java разработка|00 Java разработка]]"
2024-09-06 17:05:53 +03:00
parents:
linked:
---
Разработчики Java используют подстановочный знак (`*`) в операторах `import` для добавления всех классов из определенного пакета. Но в ходе ревью большинство из вас, возможно, просили убрать этот подстановочный знак импорта и добавить полное имя класса. Разберемся почему не стоит использовать знак подстановки?
2024-09-06 17:05:53 +03:00
Но прежде, давайте вспомним, что полное имя класса, помимо названия, содержит также пакет, например: `java.util.List`. ==Такая запись позволяет нам иметь классы с одинаковыми именами, которые находятся в разных пакетах.==
2024-09-06 17:05:53 +03:00
```java
package com.example;
public class WithoutImport {
public static void main(String[] args) {
java.util.List myList = new java.util.ArrayList();
}
}
```
Однако, полная запись весьма непрактична, поэтому в Java существует оператор импорта `import`. Операторы импорта объявляют компилятору источник имен классов, статических переменных и статических имен методов, используемых в коде. Один раз написали полное имя класса, а дальше используем только название класса.
2024-09-06 17:05:53 +03:00
```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-приложения во время выполнения.
2024-09-06 17:05:53 +03:00
## Недостатки
Так если использование подстановочного знака не приводит к проблемам производительности, то почему бы его не использовать?
### Конфликты имен
Самая серьезная проблема это возможные конфликты именования. Представьте, что у нас есть два класса из разных библиотек `org.test.Parser` и `dev.lib.Parser`. В нашем коде мы используем импорт с wildcard:
2024-09-06 17:05:53 +03:00
```java
import org.test.*
import dev.lib.*
```
Компилятор никак не отреагирует на наличие классов с одинаковыми именами в двух разных пакетах, импортируемых таким образом, если только не бу­дет предпринята попытка воспользоваться одним из этих классов.
Также проблема может возникнуть в будущем, когда вы обновите версию какую-то из библиотек. Допустим у нас была библиотека с классом `org.test.Parser`, а потом разработчик второй библиотеки тоже добавил класс `dev.lib.Parser`, таким образом мы получили конфлик именования в будущем, хотя раньше все было нормально.
2024-09-06 17:05:53 +03:00
### Чистый код
Импорты с подстановочными знаками помогают нам избежать длинного списка импортов. Следовательно, это влияет на читабельность кода, так как читателю может потребоваться прокрутить много страниц в каждом файле исходного кода, прежде чем он доберется до кода, который показывает логику. Несомненно, более читабельный код - это также чистый код.
Эта идея также поддерживается в книге "Чистый код" Роберта К. Мартина. Фактически, книга рекомендует использовать импорты с подстановочными знаками при использовании нескольких классов из одного источника. Другими словами, когда мы импортируем два или более классов, импортированных из пакета, лучше импортировать весь пакет.
Однако, я не считаю это какой-то проблемой, так как 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 эта проблема не является актуальной.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]]
**Родитель**::
**Источник**::
**Автор**::
**Создана**:: [[2024-09-06]]
### Дополнительные материалы
-
### Дочерние заметки
2024-09-14 23:38:42 +03:00
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->