太多的导入垃圾邮件我的代码

App*_*ker 12 java import coding-style package

在我的项目中,我有一个shapes包含我为我的图形程序设计的形状的包,例如Rectangle,Circle.我还有一两个与java.awt类名相同的包.

现在,因为我不想重命名我的代码库中的每个类,为了向我的源文件显示我所说的类,当我声明一个新的Rectangle时,我需要:

1-显式导入矩形类,即导入shapes.Rectangle

要么

2-只导入我需要的java.awt类而不导入java.awt.*,它自动包含awt.Rectangle

现在问题是两种方式导致大量导入,我目前在每个源文件中平均有15-25个导入,这严重地使我的代码混乱和混乱.

代码中的导入太多是件坏事吗?有没有办法解决?

Bjo*_*pen 9

是的,过多的导入是一件坏事,因为它会使您的代码变得混乱并使您的导入更具可读性.

使用通配符避免长导入列表.

Kevlin Henney在他的演讲中谈到了这个精确的Stack Overflow问题27:54 当您使用 NDC伦敦的这些企业编程技巧时,清洁编码器会讨论您的代码会发生什么? 2017年1月16日至20日

  • 根据 /sf/ask/10321811/?noredirect=1&lq=1 这很糟糕,因为它杂乱无章可能会混淆您的命名空间。 (4认同)
  • 有趣的是,我是从那个视频来到这里的。他建议使用通配符将信息减少到您正在使用的包,从而提高可读性。他没有提到这一点,但这将以编译时间为代价。大量进口是违反单一责任原则的表现。显然也存在很多耦合。简化代码将自动减少导入数量并使代码更具可读性。事实上,在演讲结束时,他准确地证明了这一点。 (3认同)
  • 同意大卫的观点,使用通配符只是隐藏了这样一个事实:您的类一开始就有太多依赖项。过多导入的解决方案就是简单地使用较少的导入;您可以通过将您的类重构为几个较小的类来实现这一点。 (3认同)
  • 我认为不使用通配符的一个重要原因是,每当有人创建类时,它们都会导致错误。这包括依赖项的更新。因此,每当您更新任何依赖项时,该更新都可能会破坏您的程序。即使更新本身不会造成破坏。这通常是一个编译错误。如果你不幸运,它也可能编译但导致运行错误或改变行为。如果不使用通配符就不存在这个问题。 (2认同)
  • 我不明白为什么这是最高答案。没有提到通配符导入的缺点。许多“企业开发人员”(指 Henney 的演讲)已经通过惨痛的教训认识到了这一点。我曾经使用通配符导入,但直到 2008 年才改用显式导入,从那时起我所有的同事都同意通配符导入会导致问题。我在下面给出了更完整的答案。 (2认同)

kel*_*ble 7

  • 如果您使用 glob 导入,则只需更新引入新类型的依赖项(通常不会是重大更改),就有可能因命名空间冲突而破坏您的代码。修复一个自由使用 glob 导入的大型代码库可能会很痛苦。这是我能想到的最有力的理由,为什么明确指定依赖项是一个好主意。
  • 阅读指定了每个导入的代码会更容易,因为您可以看到类型来自何处,而无需 IDE 特定功能和鼠标悬停,或浏览大页的库文档。许多人在 IDE 之外的代码审查、差异、git 历史记录等中阅读了大量代码。

  • 由于这些原因,我总是使用显式导入。第一个问题发生时尤其可怕。我想知道一段代码一旦编写就不会因为有人向另一个包添加新类而突然中断。我同意凯夫林·海尼的很多想法,但不同意这一点。他可能没有想到这个问题。 (5认同)

Dav*_*sel 6

我使用显式导入,并且已经这样做很多年了。在过去十年中我的所有项目中,团队成员都同意这一点,并且所有人都乐意同意使用显式导入并避免使用通配符。这并没有引起争议。

支持显式导入:

  • 使用哪些类的精确定义
  • 当代码库的其他部分发生变化时,不那么脆弱
  • 更容易进行代码审查
  • 无需猜测哪个类位于哪个包中

支持通配符:

  • 更少的代码
  • 使用文本编辑器时更容易添加和维护导入

在我职业生涯的早期,我确实使用过通配符导入,因为当时 IDE 还没有那么复杂,或者我们中的一些人只使用文本编辑器。手动管理显式导入需要相当多的工作,因此通配符导入确实很有帮助。

然而,至少有一次我被通配符导入的使用所困扰,这导致了我目前的仅显式策略。

假设您有一个具有 10 个通配符导入的类,并且它编译成功。然后,您将 5 个 jar 文件升级到较新的版本(您必须将它们全部升级,因为它们是相关的)。然后代码不再编译,出现类未找到错误。现在该类位于哪个包中?班级的全名是什么?我不知道,因为我只使用简称,现在我必须区分罐子的新旧版本,看看发生了什么变化。

如果我使用了显式导入,那么很清楚哪个类已被删除,它的包是什么,以及哪个 jar (通过查看该包中的其他类)负责。

读取代码历史或查看历史合并也存在问题。当您使用通配符导入时,读者无法确定哪个类是哪个类,因此代码更改的语义是什么。通过显式导入,您可以获得代码的精确描述,并且它可以作为更好的历史记录。

因此,总的来说,维护导入的少量额外工作和额外的代码行所带来的好处很容易被显式导入所提供的额外精度和确定性所抵消。

我仍然使用通配符的唯一情况是同一包中的导入数量超过 50 个。这种情况很少见,通常仅适用于常量。


更新 1:为了解决 Peter Mortensen 的评论,如下......

Kevlin Henney 在演讲中为使用通配符所做的唯一辩护是,名称冲突问题并不经常发生。但这发生在我身上,我从中吸取了教训。我在上面讨论过这一点。

他没有涵盖我在上面的回答中提出的所有观点。-- 但最重要的是,我认为你所做的选择,显式的还是通配符的,并不那么重要,重要的是项目/代码库中的每个人都同意并使用一致的风格。凯夫林·海尼 (Kevlin Henney) 继续谈论货物崇拜编程。我的上述决定是基于几十年来的个人经验,而不是货物崇拜的推理。

如果我要加入一个现有风格是使用通配符的项目,我会同意的。但如果我开始一个新项目,我会使用精确导入。

有趣的是,在 Node.js 中没有通配符选项。(虽然您确实有“默认”导入,但它并不完全相同)。


Buh*_*ndi 5

另一种替代方法是根据需要键入完全限定的类名。在我的示例中,有 2 个Element对象,一个是我创建的org.opensearch.Element,另一个是org.w3c.dom.Element.

为了解决名称冲突,以及尽量减少导入“混乱”,我已经这样做了(在我的org.opensearch.Element课堂上):

public org.w3c.dom.Element toElement(org.w3c.dom.Document doc) { /* .... */ }
Run Code Online (Sandbox Code Playgroud)

如您所见,返回Element类型是全类型的(即我指定了 的全限定类名Element)。

问题解决了!:-)


sti*_*vlo 5

  • 按类导入类而不是导入整个包是一种很好的做法

  • 任何好的IDE(例如Eclipse)都会在一行中折叠导入,并且您可以在需要时展开它们,这样它们就不会使您的视图混乱

  • 如果发生冲突,您可以始终引用完全限定的类,但如果您控制的是这两个类中的一个,则可以考虑重命名它.(使用Eclipse,右键单击该类,选择Refactor -> Rename,它将注意更新其所有引用).

  • 如果你的班级是从AWT和你的形状包导入的,那没关系.可以从几个类导入; 但是,如果你发现自己从很多不同的来源进口,这可能表明你的班级做得太多了,需要分开.

  • 这个答案不包含任何关于为什么最好使用显式导入而不是通配符的论据,而是只说明“IDE 使它不那么痛苦”,即治疗症状,而不是原因。这就是我决定否决这个答案的原因。 (5认同)
  • 对我来说,当我通过 Github 或任何文本编辑器阅读代码时,我可以准确地知道 `ThirdPartyClass` 驻留在哪个类中。而不是递归地查看那些 6-7 个 `*` 导入的类。另一个例子,当我打开一个遗留项目时,其中 2-3 个库不可用。他们使用了 * 导入,并且很难知道不可找到的类来自哪个包。只有当他们使用明确的名称时,从包名称中就可以很容易地做到这一点。 (2认同)