



Единственная проблема в том, что он загромождает ваше локальное пространство имен. Например, предположим, что вы пишете приложение Swing, и поэтому вам нужен java.awt.Event, а также вы взаимодействуете с системой календаря компании, в которой есть com.mycompany.calendar.Event. Если вы импортируете и то, и другое с помощью метода подстановки, произойдет одно из трех:
java.awt.Event и com.mycompany.calendar.Event, и вы даже не можете скомпилировать..*), но он неправильный, и вам сложно понять, почему ваш код утверждает, что тип неправильный.com.mycompany.calendar.Event отсутствует, но когда они позже добавляют его, ваш ранее действующий код внезапно перестает компилироваться.Преимущество явного перечисления всего импорта состоит в том, что я могу сразу определить, какой класс вы собираетесь использовать, что значительно упрощает чтение кода. Если вы просто делаете что-то одноразовое, в нем нет ничего явного неправильный, но в противном случае будущие сопровождающие будут благодарить вас за вашу ясность.
Обязательно ознакомьтесь с моим комментарием ниже - есть большая проблема с типами, которые со временем добавляются в сторонние библиотеки. У вас может быть компилируемый код, который перестает компилироваться после того, как кто-то добавит тип в jar, от которого вы зависите.
Что касается вопроса 1: технически вы можете скомпилировать, но вам придется каждый раз использовать полное имя класса.
Вы можете разрешить такие конфликты, не перечисляя явно каждый класс, что само по себе вызывает проблемы.
Я удивлен, что этот ответ был принят и набрал более 500 голосов. Буквально, когда компиляторы находят что-то для вас, это хорошо, а не плохо. Я до сих пор не встречал ни одного аргумента об импорте звездочек, который отвечал бы ежедневным потребностям разработчиков и не связан с авторитаризмом Checkstyle.
Я предпочитаю определенный импорт, потому что он позволяет мне видеть все внешние ссылки, используемые в файле, не просматривая файл целиком. (Да, я знаю, что здесь не обязательно будут отображаться полностью квалифицированные ссылки. Но я по возможности избегаю их.)
Он загромождает ваше пространство имен, требуя от вас полного указания любых неоднозначных имен классов. Чаще всего это происходит с:
import java.util.*;
import java.awt.*;
...
List blah; // Ambiguous, needs to be qualified.
Это также помогает сделать ваши зависимости конкретными, поскольку все ваши зависимости перечислены в верхней части файла.
В большинстве мест, где я работал, где используется значительное количество Java, явный импорт является частью стандарта кодирования. Иногда я все еще использую * для быстрого прототипирования, а затем расширяю списки импорта (некоторые IDE также сделают это за вас) при создании кода.
Мне нравится большинство ваших пунктов, но именно №4 заставило меня проголосовать за ваш ответ. Современные IDE удаляют большинство аргументов против использования явного импорта ...
Возможно, часть проблемы здесь заключается в том, как стандартные библиотеки Java размещаются со многими классами в одном пакете. В отличие от применения «принципа единой ответственности» к пакету.
Вот голосование за импорт звезд для. Оператор импорта предназначен для импорта упаковка, а не класса. Гораздо проще импортировать целые пакеты; проблемы, указанные здесь (например, java.sql.Date против java.util.Date), легко устраняются другими способами, а не В самом деле, решаемым конкретным импортом, и, конечно же, не оправдывают безумно педантичный импорт для всех классов. Нет ничего более обескураживающего, чем открытие исходного файла и необходимость пролистать 100 операторов импорта.
Выполнение определенного импорта затрудняет рефакторинг; если вы удаляете / переименовываете класс, вам нужно удалить все из его конкретных импортов. Если вы переключите реализацию на другой класс в том же пакете, вам придется исправить импорт. Хотя эти дополнительные шаги можно автоматизировать, они действительно снижают производительность без реальной выгоды.
Если бы Eclipse не выполнял импорт определенных классов по умолчанию, все бы все равно выполняли импорт звездочек. Извините, но на самом деле нет никакого рационального оправдания для конкретного импорта.
Вот как справляться с конфликтами классов:
import java.sql.*;
import java.util.*;
import java.sql.Date;
Я согласен. Хотя я не возражаю против использования явного импорта, я все же предпочитаю использовать импорт звездочки. Они подчеркивают, что «единица повторного использования» - это весь пакет, а не его отдельные типы. Другие причины, перечисленные против импорта звезд, являются слабыми, и, по моему опыту, использование импорта звезд никогда не вызывало реальных трудностей.
См. javadude.com/articles/importondemandisevil.html, чтобы узнать, почему это зло. Основная идея: это может привести к прекращению компиляции кода, когда классы являются добавлен для пакетов, которые вы импортируете (например, когда List был добавлен в java.util ...)
Надежное управление конфигурацией и непрерывная интеграция могут тривиально решить эту проблему, и у вас нет явных имен классов, засоряющих ваш код. Я согласен, что это плохой языковой дизайн, но его очень просто обойти
Все упомянутые вами проблемы могут быть решены с помощью современных IDE (сокрытие импорта, рефакторинг имени класса и т. д.).
Мне не нужно использовать IDE для чтения или записи исходного кода - код должен быть читаемым сам по себе без специальных инструментов, если только язык не является невероятно тупым. В этом случае Java отлично работает - просто используйте импорт звездочки. Нет причин не делать этого.
Импорт статических звезд дает прирост производительности. Удобно просто набрать assertTrue и т. д. Моя среда IDE настроена с использованием правил стиля проверки для моей работы, которые их запрещают. Затем для добавления статического импорта требуется преобразование существующего импорта (вручную или с помощью ярлыка). В этот момент я могу либо вручную изменить импорт на звезду (необходимо изменить позже), либо повторить описанный выше процесс для всех других методов / констант / перечислений, которые я использую. Это незначительное, но реальное нарушение. Список был неудачным; Я никогда не сталкивался с этой или подобной проблемой. Спасибо за внимание.
@ davetron5000 Вам не нужно использовать IDE для чтения или записи исходного кода. Все приличные текстовые редакторы также поддерживают сворачивание.
Даже дядя Боб рекомендует выполнять импорт пакетов в своей книге «Чистый код». Для меня это достаточно веская причина использовать их.
@ davetron5000 Если ваш код содержит 10+ импортированных подстановочных знаков, и вы используете класс Foo, и если я прочитал ваш код без использования IDE (поскольку ваш аргумент состоит в том, что мне не нужно его использовать), как я узнаю, какой пакет Foo пришли из? Конечно, при использовании IDE среда IDE сообщит мне об этом, но весь ваш аргумент состоит в том, что я должен иметь возможность читать кода без него. Выполнение явного импорта помогает задокументируйте код(отличная причина избегать использования подстановочных знаков), и гораздо более вероятно, что я буду кодом чтение без использования IDE, чем пишу кодом без использования IDE.
Ответ: «Оператор импорта предназначен для импорта пакета, а не класса». Моя IDE: [Java] Only a type can be imported. org.springframework.stereotype resolves to a package
Если у вас есть сотня импортов, скорее всего, ваш класс слишком велик и, вероятно, отвечает более чем за одну вещь. Проблема здесь не в импорте, а в написанном коде. Вы должны избавиться от испорченного материала, вместо того, чтобы делать его красивым, придавая ему форму цветка. ;)
@ davetron5000 Вы опровергли свой аргумент. Чтобы код «читался сам по себе без специальных инструментов», у вас должен быть полностью квалифицированный импорт. Используя импорт с подстановочными знаками, вы не знаете, откуда берется класс, без поиска по пакетам или использования справки при наведении курсора IDE.
Некоторое время назад я был программистом по обслуживанию. У меня часто был код читать на Github или vi. Проблема с начальным импортом в том, что очень сложно найти, откуда берется этот определенный класс. Худшим способом было выполнить поиск по всему репозиторию или выполнить команду grep, оба варианта кажутся излишними. Я хотел, чтобы люди не использовали * импорт. И теперь я не знаю, сказано ли об этом в «Чистом коде».
@GaneshSatpute Итак, вы только что доказали, что вам не следует использовать GitHub или vi для просмотра репозиториев. Я считаю, что правило «не следует использовать специальные инструменты для чтения кода» не годится. Мы профессионалы, мы должны использовать оптимальные (если не самые лучшие) инструменты, а не наоборот.
@ user3157855 Я точно ничего не доказал. Я до сих пор использую vi, Github, а также современные IDE. Я стараюсь быть непредубежденным, я не буду считать кого-то «непрофессиональным», потому что он использует vi или Github, чтобы показать кому-то код, или быстро посмотреть на реализацию, а не клонировать репозиторий и настраивать его локально.
пожалуйста, смотрите мою статью Импорт по требованию - это зло
Короче говоря, самая большая проблема заключается в том, что ваш код может сломаться, когда класс добавлен для импортируемого вами пакета. Например:
import java.awt.*;
import java.util.*;
// ...
List list;
В Java 1.1 это было нормально; Список найден в java.awt, и конфликта нет.
Теперь предположим, что вы вернули свой отлично работающий код, а год спустя кто-то другой принесет его для редактирования и использует Java 1.2.
В Java 1.2 в java.util добавлен интерфейс с именем List. БУМ! Конфликт. Совершенно рабочий код больше не работает.
Это особенность языка ЗЛО. Существует причина НЕТ, по которой код должен перестать компилироваться только потому, что тип добавлен для пакета ...
Кроме того, читателю сложно определить, какой «Foo» вы используете.
Это не оправдание. Если вы меняете версию java, вы каким-то образом ожидаете, что что-то не удастся, то же самое, если вы измените версию двоичного файла, который использует ваш код. В этих случаях код выдает ошибку компиляции, и ее легко исправить (см. Предыдущий ответ: stackoverflow.com/a/149282/7595)
@PabloFernandez - Нет - если я проверю код, который хранился в репозитории в течение года, он все равно должен компилироваться. Импорт по требованию может легко завершиться ошибкой, если новые классы имеют значение добавлен для существующих пакетов, которые я импортировал. Это проблема не только при обновлении версий Java. Также - если API спроектирован хорошо, никогда должен нарушить существующий код при обновлении. Единственный раз, когда мне потребовалось изменить код при обновлении версий java, было из-за импорта по запросу и когда Sun втянула XML API в среду выполнения java.
Я придаю большое значение языковой функции, которая заставляет некогда компилируемый код прекращать компиляцию, когда вы добавляете что-то в путь к классу. Очень большая проблема, особенно когда сопровождающий берет код, который они не писали - как они узнают намерение, не изучая код какое-то время - код, который раньше компилировался и отлично работал ... Почему они должны его менять только потому, что к пути компиляции был добавлен новый jar или обновлен JDK?
Путь к классам - это фундаментальный компонент процесса компиляции. Если вы думаете, что произвольное изменение пути к классам не повлияет на ваш однажды скомпилированный код, то вы, мягко говоря, наивны.
ДОБАВЛЕНИЕ класса (с уникальным, полностью определенным именем!) В путь к классам не должно ни на что влиять. Дело в том, что если вы не используете синтаксис импорта по запросу, этого не произойдет. Так что не используйте плохой синтаксис, который, к сожалению, допускает язык, и это еще одна реальная проблема, с которой вы можете столкнуться.
Суть моего ответа в том, что это ненужная языковая функция, которая вызывает проблемы. Многие IDE / редакторы автоматически обрабатывают расширение импорта. Используйте полностью квалифицированный импорт, и вероятность возникновения этой конкретной ошибки отсутствует. Меня поразило это, когда я был вынужден исправить ошибку в существующем коде, и вам действительно не нужно что-то подобное, чтобы отвлечься от реальной задачи. java.util.List против java.awt.List не так уж и плохо, чтобы понять, но попробуйте, когда имя класса - Configuration, и несколько библиотек зависимостей добавили его в свою последнюю версию репозитория maven.
Если я обновлю jar-файл, в котором классы, которые я использую, совместимы с API-forward, И я не использую синтаксис импорта по запросу, это никак не повлияет на меня. Это имеет для вас смысл? Не поленитесь определить импорт, и это не проблема. Синтаксис импорта по запросу был ошибкой в определении языка Java; разумный язык не должен допускать подобных ошибок.
В статье Скотта он утверждает, что если бы Sun создала java.util.collections.List вместо java.util.List, не было бы конфликта с java.awt.List. Это почему?
@SheldonR., Потому что, если бы они изобрели новый пакет (java.util.collections) для List, у устаревшего кода не было бы риска импортировать его по ошибке.
@aioobe Разве java.util.collections не будет подхвачен java.util. *?
@aioobe Пакеты в Java - это просто уникальные имена. Они могут выглядеть как вложенные имена из-за общих префиксов, но они никогда не имеют отношения к другим пакетам. (Обратите внимание, что они имеют общие структуры родительских каталогов, но это просто удобство среды, а не определение языка ...)
Думаю, ваш комментарий должен был быть адресован SheldonR.
@aioobe (я хотел, чтобы он перешел к вам, чтобы добавить пояснение, почему java.util.collections не будет получен при импорте java.util. *)
Хорошо, спасибо за ваш комментарий, но вам не нужно учить меня, как работают пакеты Java. :-D (Я зарабатываю на жизнь компилятором OpenJDK Java ;-)
Обратите внимание, что конкретный импорт имеет приоритет над импортом с подстановочными знаками. import java.awt.*; import java.util.*; import java.util.List; достаточно, чтобы устранить неквалифицированный List. Это намного чище, чем называть каждый класс.
@Kevin Импорт подстановочных знаков Любые подвергает вас риску того, что код не компилируется при добавлении новой сторонней зависимости или обновлении до более поздней версии Java. Имея доступные IDE, вы всегда можете свернуть список импорта, чтобы не смотреть на него
@ScottStanchfield Обновление часто вызывает незначительные головные боли, но вероятность того, что обновление приведет к тому, что ранее однозначное имя станет неоднозначным, довольно редка, так что не стоит беспокоиться.
И, на мой взгляд, «читабельность в среде IDE» недостаточно. Код должен быть легко читаемым в любом текстовом редакторе, даже в тех, которые не выполняют сворачивание импорта или кода.
@Kevin - проблема заключается между удобочитаемостью в редакторах, которые не поддерживают сворачивание (я бы сказал, что не большинство из используемых), и огромным потенциалом ошибок компилятора, вносимых изменениями библиотеки. Я видел, как этот потенциал реализовывался много раз (самый ранний и самый отвратительный - List в java.util. * И java.awt. *), Потому что разработчики используют импорт по запросу, и это чаще всего влияет на человека, поддерживающего код. год или более спустя, что обременяет их за счет читабельности вашего слабого редактора. Не обременяйте своих сопровождающих. И получите лучший редактор.
В любом случае скомпилированное приложение будет продолжать работать с новыми выпусками Java независимо от того, как вы импортировали. Сбой в процессе сборки, а не в приложении. При обновлении до новой версии Java SDK ваши инструменты сборки сообщат вам, что у вас возникла проблема. Есть много причин, по которым обновление SDK может пойти не так, и это лишь одна из них. В конечном итоге использование явного импорта может сэкономить ваше время, но использование подстановочных знаков не является злом по своей сути, если вы об этом знаете.
Также возвращение к Java 1.1 -> Java 1.2 в качестве примера недопустимо. Это было ГЛАВНОЕ изменение парадигмы, и тонна существующего кода Java сломалась во время этого перехода.
В предыдущем проекте я обнаружил, что переход от * -imports к конкретному импорту сокращает время компиляции вдвое (с примерно 10 минут до примерно 5 минут). * -Import заставляет компилятор искать в каждом из перечисленных пакетов класс, соответствующий тому, который вы использовали. Это время может быть небольшим, но для больших проектов оно подходит.
Побочным эффектом * -import было то, что разработчики копировали и вставляли общие строки импорта, а не думали о том, что им нужно.
Для этого должно быть много строк импорта или система разработки действительно жалкий. Я использую import- * и могу скомпилировать свой вся кодовая база из 2107 классов менее чем за 2 минуты.
нет - плохо использовать подстановочный знак с оператором импорта Java.
В Чистый код Роберт С. Мартин фактически рекомендует использовать их, чтобы избежать длинных списков импорта.
Вот рекомендация:
J1: Avoid Long Import Lists by Using Wildcards
If you use two or more classes from a package, then import the whole package with
import package.*;
Long lists of imports are daunting to the reader. We don’t want to clutter up the tops of our modules with 80 lines of imports. Rather we want the imports to be a concise statement about which packages we collaborate with.
Specific imports are hard dependencies, whereas wildcard imports are not. If you specifically import a class, then that class must exist. But if you import a package with a wildcard, no particular classes need to exist. The import statement simply adds the package to the search path when hunting for names. So no true dependency is created by such imports, and they therefore serve to keep our modules less coupled.
There are times when the long list of specific imports can be useful. For example, if you are dealing with legacy code and you want to find out what classes you need to build mocks and stubs for, you can walk down the list of specific imports to find out the true qualified names of all those classes and then put the appropriate stubs in place. However, this use for specific imports is very rare. Furthermore, most modern IDEs will allow you to convert the wildcarded imports to a list of specific imports with a single command. So even in the legacy case it’s better to import wildcards.
Wildcard imports can sometimes cause name conflicts and ambiguities. Two classes with the same name, but in different packages, will need to be specifically imported, or at least specifically qualified when used. This can be a nuisance but is rare enough that using wildcard imports is still generally better than specific imports.
Я бы посоветовал Роберту К. Мартину использовать лучшие шаблоны для создания более сжатых пакетов и собственных классов, не требующих 80 строк импорта. То, что множество классов, необходимых для импорта внутри одного класса, просто умоляет: «Энтропия, энтропия, сломай меня, пожалуйста ...» и указывает причину, по которой следует избегать импорта *, изложенную в ответах Скотта Стэнчфилдса.
Хотя мне вообще нравится то, что говорит дядя Боб, в этом случае я также вынужден с ним не согласиться.
Просто чтобы обеспечить некоторый противовес, когда дело доходит до цитирования авторитетов по этой проблеме: Руководство по стилю Google Java, а также Руководство по стилю Java в Twitter (который в значительной степени основан на Google, чтобы быть справедливым) специально запрещают импорт подстановочных знаков. Но они не дают никакого обоснования этому решению.
Наверное, единственное, с чем я не согласен в Clean Code. Ему приходится прокручивать несколько строк операторов импорта или изо всех сил пытаться найти, откуда взялся класс. Я предпочитаю легко определять происхождение определенного класса.
Представление: не влияет на производительность, так как байт-код такой же. хотя это приведет к некоторым накладным расходам на компиляцию.
Компиляция: на моей персональной машине компиляция пустого класса без импорта чего-либо занимает 100 мс, но тот же класс при импорте java. * Занимает 170 мс.
import java.* ничего не импортирует. Какая разница?
Это имеет значение, потому что он ищется во время компиляции.
Я чувствую, что это сравнение не согласуется с вопросом, потому что оно сравнивает ничего такого с импортом подстановочного знака. Мне было бы любопытно, какова разница во времени компиляции при импорте класса через подстановочный знак по сравнению с конкретным. А поскольку компилятор «ищет» в пакете подстановочный знак, я предполагаю, что разница во времени зависит от размера пакета и количества импортированных классов из того же пакета.
In whatever development technology the implementation will be based on, look for ways of minimizing the work of refactoring MODULES . In Java, there is no escape from importing into individual classes, but you can at least import entire packages at a time, reflecting the intention that packages are highly cohesive units while simultaneously reducing the effort of changing package names.
И если он загромождает локальное пространство имен, это не ваша вина - виноват размер пакета.
Наиболее важным из них является то, что импорт java.awt.* может сделать вашу программу несовместимой с будущей версией Java:
Предположим, у вас есть класс с именем «ABC», вы используете JDK 8 и импортируете java.util.*. Теперь предположим, что выходит Java 9, и у нее есть новый класс в пакете java.util, который по совпадению также называется «ABC». Теперь ваша программа не будет компилироваться на Java 9, потому что компилятор не знает, имеете ли вы под именем «ABC» свой собственный класс или новый класс в java.awt.
У вас не возникнет этой проблемы, если вы явно импортируете из java.awt только те классы, которые вы действительно используете.
Ресурсы:
совет: вы могли бы использовать Stream в качестве примера нового класса, добавленного в Java в java.util в Java 8 ...
Среди всех допустимых моментов, высказанных с обеих сторон, я не нашел своей основной причины избегать подстановочного знака: мне нравится иметь возможность читать код и напрямую знать, что такое каждый класс, или его определение не на языке или файл, где его найти. Если с помощью * импортировано более одного пакета, мне нужно поискать каждый из них, чтобы найти класс, который я не узнаю. Читаемость на высшем уровне, и я согласен, что код не должен требовать IDE для его чтения.
Если вы доведете это до полного логического завершения, тогда ваш стиль должен заключаться в том, чтобы вообще не использовать импорт, а вместо «нового LinkedList» всегда использовать «new java.util.LinkedList» и делать это последовательно везде.
Это не влияет на время выполнения, поскольку компилятор автоматически заменяет * конкретными именами классов. Если вы декомпилируете файл .class, вы никогда не увидите import ...*.
C# всегда использует * (неявно), поскольку вы можете только имя пакета using. Вы вообще никогда не можете указывать имя класса. В Java эта функция появилась после C#. (Java очень сложна во многих аспектах, но это выходит за рамки этой темы).
В Intellij Idea, когда вы "организуете импорт", он автоматически заменяет несколько импортированных одного и того же пакета на *. Это обязательная функция, так как вы не можете отключить ее (хотя вы можете увеличить порог).
Случай, указанный в принятом ответе, недействителен. Без * у вас все еще та же проблема. Вы должны указать имя pakcage в своем коде, независимо от того, используете вы * или нет.
В IntelliJ это не обязательная функция, и ее можно отключить.
Для записи: Когда вы добавляете импорт, вы также указываете свои зависимости.
Вы могли быстро увидеть, каковы зависимости файлов (за исключением классов одного и того же пространства имен).
Соглашаться. Мотиватор не столько в производительности или компиляции, сколько в удобочитаемости вашего кода. Представьте, что вы читаете код без IDE - например, на GitHub. Внезапно поиск каждой ссылки, не определенной в файле, который вы читаете, становится утомительно утомительно.
Импорт всех классов в пакете считается слепым подходом. Основная причина этого в том, что это загромождает пространство имен классов и может привести к конфликтам между классами в разных пакетах с одинаковыми именами.
Специальное заполнение необходимых классов позволяет избежать этой проблемы и ясно показывает, какие версии нужны. Это хорошо для удобства сопровождения кода.
Забудьте о загроможденных пространствах имен ... И подумайте о бедняге, который должен читать и понимать ваш код на GitHub, в vi, Notepad ++ или в каком-либо другом текстовом редакторе, отличном от IDE.
Этот человек должен тщательно искать каждый токен, исходящий от одного из подстановочных знаков, по всем классам и ссылкам в каждой области с подстановочными символами ... просто чтобы понять, что, черт возьми, происходит.
Если вы пишете код только для компилятора - и вы знаете, что делаете - я уверен, что с подстановочными знаками проблем нет.
Но если другие люди - включая вас будущего - хотят быстро разобраться в конкретном файле кода за одно чтение, тогда явные ссылки очень помогают.
Вот несколько вещей, которые я нашел по этой теме.
Во время компиляции компилятор пытается найти классы, которые используются в коде из. * Import, и соответствующий байт-код будет сгенерирован путем выбора используемых классов из. * Import. Таким образом, байтовый код использования. * Import или .class names import будет таким же, и производительность во время выполнения также будет такой же из-за того же байтового кода.
В каждой компиляции компилятор должен сканировать все классы пакета. * На соответствие классам, которые фактически используются в коде. Таким образом, код с. * Import занимает больше времени в процессе компиляции по сравнению с использованием импорта имени .class.
Использование. * Import помогает сделать код более чистым
Использование. * Import может создать двусмысленность, когда мы используем два класса с одинаковым именем из двух разных пакетов. Например, Дата доступна в обоих пакетах.
import java.util.*;
import java.sql.*;
public class DateDemo {
private Date utilDate;
private Date sqlDate;
}
Это первый сценарий, который случится. Компилятор замечает наличие двух классов событий и выдает ошибку.