Почему использование wild card с инструкцией импорта Java плохо?

гораздо удобнее и чище использовать один оператор, как

import java.awt.*;

чем импортировать кучу отдельных классов

import java.awt.Panel;
import java.awt.Graphics;
import java.awt.Canvas;
...

что не так с использованием подстановочного знака в import заявление?

13 ответов


единственная проблема в том, что он загромождает ваше локальное пространство имен. Например, предположим, что вы пишете приложение Swing, и поэтому вам нужно java.awt.Event, а также взаимодействуют с системой календаря компании, которая имеет com.mycompany.calendar.Event. Если вы импортируете оба метода с помощью подстановочного знака, происходит одно из этих трех событий:

  1. у вас есть прямой конфликт имен между java.awt.Event и com.mycompany.calendar.Event, и поэтому вы даже не можете скомпилировать.
  2. на самом деле вам удается только импортировать один (только один из ваших двух импорта делает .*), но это неправильный, и вы изо всех сил пытаетесь понять, почему ваш код утверждает, что тип неправильный.
  3. при компиляции кода нет com.mycompany.calendar.Event, но когда они позже добавляют один, ваш ранее действительный код внезапно прекращает компиляцию.

преимущество явного перечисления всех импорта заключается в том, что я могу сразу сказать, какой класс вы хотели использовать, что просто делает чтение кода намного проще. Если вы просто делая быструю одноразовую вещь, нет ничего явно неправильно, но будущие сопровождающие поблагодарят вас за вашу ясность в противном случае.


вот голосование на звезда импорта. Оператор import предназначен для импорта пакета, а не класс. Гораздо чище импортировать целые пакеты; проблемы, указанные здесь (например,java.sql.Date vs java.util.Date) легко исправляются другими средствами, а не действительно адресовано конкретным импортом и, конечно, не оправдывает безумно педантичный импорт по всем классам. Нет ничего более обескураживающего, чем открытие исходного файла и необходимость просмотра страницы 100 операторов импорта.

выполнение определенного импорта затрудняет рефакторинг; если вы удалите / переименуете класс, вам нужно удалить все своего специфического импорта. Если вы переключаете реализацию на другой класс в том же пакете, вам нужно исправить импорт. Все эти дополнительные шаги могут быть автоматизированы, они действительно производительность делает без выгоды.

даже если Eclipse не выполнял импорт классов по умолчанию, все равно все будут делать star импортозамещающий. Извините, но на самом деле нет никакого рационального оправдания для конкретного импорта.

вот как бороться с классовыми конфликтами:

import java.sql.*;
import java.util.*;
import java.sql.Date;

пожалуйста, смотрите мою статью импорт по требованию-это зло

короче, самая большая проблема заключается в том, что ваш код может сломаться когда класс добавил в пакет импорта. Например:

import java.awt.*;
import java.util.*;

// ...

List list;

в Java 1.1 это было нормально; список был найден в java.awt и конфликта не было.

теперь предположим, что вы проверяете свой отлично работающий код, а через год кто - то другой выводит его для редактирования и использует Java 1.2.

Java 1.2 добавлен интерфейс с именем List в java.утиль. Бум! Конфликт. Отлично работающий код больше не работает.

Это зло функции языка. Есть нет причина, по которой код должен прекратить компиляцию только потому, что тип добавил в пакет...

кроме того, читателю трудно определить, какой "Foo" вы используете.


Это не плохо использовать wild card с инструкцией импорта Java.

на Код, Robert C. Martin фактически рекомендует использовать их, чтобы избежать длинных списков импорта.

вот рекомендации:

J1: избегайте длинных списков импорта с помощью Шаблоны

Если вы используете два или более классов из пакет, затем импортируйте весь пакет с

импорт пакета.*;

длинные списки импорта являются сложными для читатель. Мы не хотим беспорядка. до вершины наши модули с 80 линии импорта. А мы хотим импорт, чтобы быть кратким заявлением о каких пакетах мы сотрудничаем с.

специфический импорт трудн зависимости, тогда как импорт подстановочных знаков не. Если вы конкретно импорт класс, тогда этот класс должен существовать. Но если вы импортируете пакет с подстановочный знак, никаких конкретных классов не нужно иметь место. Оператор import просто добавляет пакет в путь поиска в поисках имен. Так что это неправда. зависимость создается таким импортом, и они поэтому служат для того чтобы держать наше модули менее сцеплены.

бывают случаи, когда длинный список конкретный импорт может быть полезен. Для например, если вы имеете дело с устаревший код и вы хотите узнать какие классы вам нужно построить глумится и заглушки для, Вы можете идти вниз список конкретных импорта, чтобы узнать истинные имена всех тех классы, а затем поставить соответствующий заглушки на месте. Однако, эта польза для специфический импорт очень редок. Кроме того, большинство современных ИД будут позволяет конвертировать wildcarded импорт в список конкретных импортных товаров одной командой. Так что даже в legacy case лучше импортировать подстановочный знак.

импорт подстановочных знаков иногда может вызвать конфликты имен и двусмысленности. Два классы с тем же именем, но в отличающийся пакеты должны быть специально импортированные или, по крайней мере, особо квалифицированный при использовании. Этот может быть неприятно, но достаточно редко что использование импорта подстановочных знаков по-прежнему как правило, лучше, чем конкретные импортозамещающий.


он загромождает пространство имен, требуя полного указания любых неоднозначных имен классов. Наиболее распространенным случаем этого является:

import java.util.*;
import java.awt.*;

...
List blah; // Ambiguous, needs to be qualified.

Это также помогает сделать ваши зависимости конкретными, так как все ваши зависимости перечислены в верхней части файла.


производительность: отсутствие влияния на представлении по мере того как код байта такое же. хотя это приведет к некоторым накладным расходам на компиляцию.

сборник: на моей личной машине компиляция пустого класса без импорта чего-либо занимает 100 мс, но тот же класс при импорте java.* принимает 170 МС.


  1. это помогает идентифицировать конфликты имен классов: два класса в разных пакетах с одинаковыми именами. Это можно замаскировать с помощью * import.
  2. это делает зависимости явными, так что любой, кто должен прочитать ваш код позже, знает, что вы хотели импортировать и что вы не хотели импортировать.
  3. он может сделать некоторую компиляцию быстрее, потому что компилятору не нужно искать весь пакет для определения depdencies, хотя это обычно не очень важно с современными компиляторами.
  4. неудобные аспекты явного импорта минимизируются с помощью современных IDE. Большинство IDE позволяют свернуть раздел импорта, чтобы он не мешал, автоматически заполнять импорт, когда это необходимо, и автоматически идентифицировать неиспользуемые импорт, чтобы помочь очистить их.

большинство мест, где я работал, которые используют любое значительное количество Java, делают явный импорт частью стандарта кодирования. Иногда я все еще использую * для быстрого прототипирования, а затем разверните списки импорта (некоторые IDE сделают это и для вас) при создании кода.


Я предпочитаю конкретный импорт, потому что он позволяет мне видеть все внешние ссылки, используемые в файле, не глядя на весь файл. (Да, я знаю, что это не обязательно показывать полные ссылки. Но я избегаю их, когда это возможно.)


в предыдущем проекте я обнаружил, что переход от *-импорта к конкретному импорту сократил время компиляции вдвое (примерно с 10 минут до примерно 5 минут). * - Импорт заставляет компилятор искать каждый из пакетов, перечисленных для класса, соответствующего тому, который вы использовали. Хотя это время может быть небольшим, оно складывается для больших проектов.

побочным эффектом * - импорта было то, что разработчики копировали и вставляли общие строки импорта, а не думали о том, что им нужно.


на DDD книга

в любой технологии развития реализация будет основана на, искать способы минимизации работа рефакторинга модулей . В Java нет возможности избежать импорта в отдельные классы, но вы может по крайней мере импортировать целые пакеты за один раз, отражая намерение, что пакеты являются очень сплоченными единицами при одновременном снижении усилий по изменению имен пакетов.

и если это загромождает локальное пространство имен не ваша вина-виноват размер пакета.


наиболее важным является то, что импорт java.awt.* может сделать вашу программу несовместимой с будущей версией Java:

предположим, что у вас есть класс с именем "ABC", вы используете JDK 8 и импортируете java.util.*. Теперь предположим, что Java 9 выходит, и у него есть новый класс в package java.util что по совпадению также называется "ABC". Ваша программа теперь не будет компилироваться на Java 9, потому что компилятор не знает, имеете ли вы в виду свой собственный класс или новый класс java.awt.

у вас не будет этой проблемы, когда вы импортируете только эти классы явно из java.awt что вы на самом деле использовать.

ресурсы:

Импорт Java


среди всех допустимых точек, сделанных с обеих сторон, я не нашел своей основной причины избегать подстановочного знака: мне нравится иметь возможность читать код и напрямую знать, что такое каждый класс, или если это определение не на языке или файле, где его найти. Если более одного пакета импортируется с*, я должен искать каждый из них, чтобы найти класс, который я не узнаю. Читаемость является высшей, и я согласен, что код не должен require IDE для чтения.


  • нет влияния времени выполнения, так как компилятор автоматически заменяет * конкретными именами классов. Если вы декомпилируете .файл класса, вы никогда не увидите import ...*.

  • C# всегда использует * (неявно), как вы можете только using имя пакета. Вы не можете указать имя класса в целом. Java вводит функцию после c#. (Java настолько сложно во многих аспектах, но это выходит за рамки этой темы).

  • В Intellij Идея когда вы делаете "организовать импорт", он автоматически заменяет несколько импорта одного и того же пакета с *. Это особенность обязателен, так как вы не можете выключить его (Хотя вы можете увеличить порог).

  • случай, указанный в принятом ответе, недействителен. Без * У вас все та же проблема. Вам нужно указать имя pakcage в коде независимо от того, используете вы * или нет.