为什么在Java导入语句中使用通配符不好?

时间:2020-03-06 14:51:34  来源:igfitidea点击:

使用单个语句像

import java.awt.*;

而不是导入一堆单独的类

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

在import语句中使用通配符有什么问题?

解决方案

唯一的问题是,它会使本地名称空间混乱。例如,假设我们正在编写一个Swing应用程序,因此需要java.awt.Event,并且还与该公司的日历系统接口,该日历系统具有com.mycompany.calendar.Event。如果我们同时使用通配符方法导入这两种情况,则会发生以下三种情况之一:

  • 我们在java.awt.Event和com.mycompany.calendar.Event之间存在完全的命名冲突,因此甚至无法编译。
  • 实际上,我们实际上只能导入一个(两个导入中只有一个执行"。*"),但这是错误的,并且我们很难弄清楚为什么代码声称类型是错误的。
  • 当我们编译代码时,没有com.mycompany.calendar.Event,但是当他们以后添加一个代码时,我们先前有效的代码突然停止编译。

显式列出所有导入的优点是,我可以一目了然地告诉我们要使用哪个类,这使阅读代码变得更加容易。如果我们只是快速完成一项操作,那么就没有明显的错误,但是以后的维护人员将感谢清晰说明。

我更喜欢特定的导入,因为它使我可以查看文件中使用的所有外部引用,而无需查看整个文件。 (是的,我知道它不一定会显示完全合格的参考。但是我会尽可能避免使用它们。)

它会使名称空间混乱,要求我们完全指定任何模棱两可的类名。最常见的情况是:

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

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

由于所有依赖项都列在文件顶部,因此还有助于使依赖项具体化。

  • 它有助于识别类名冲突:不同程序包中的两个类具有相同的名称。这可以用* import掩盖。
  • 它使依赖关系明确,以便以后必须阅读代码的任何人都知道我们要导入的内容和我们不想要导入的内容。
  • 它可以使某些编译速度更快,因为编译器不必搜索整个程序包来确定依赖关系,尽管对于现代编译器而言,这通常不是什么大问题。
  • 显式导入的不便之处通过现代IDE得以最小化。大多数IDE允许我们折叠导入部分,以免妨碍导入,在需要时自动填充导入,并自动识别未使用的导入以帮助清理它们。

我工作过的大多数使用大量Java的地方都将显式导入作为编码标准的一部分。在生产代码时,有时我仍使用*进行快速原型制作,然后扩展导入列表(某些IDE也会为我们完成此操作)。

这是明星进口的投票。 import语句用于导入软件包,而不是类。导入整个软件包要干净得多。此处确定的问题(例如,java.sql.Date和java.util.Date)可以通过其他方式轻松解决,无法通过特定的导入方式真正解决,当然也不能为所有类的疯狂的学究式导入辩护。没有什么比打开源文件并翻阅100条import语句更令人不安的了。

进行特定的进口使重构更加困难;如果删除/重命名一个类,则需要删除其所有特定的导入。如果将实现切换到同一包中的其他类,则必须修复导入。尽管这些额外的步骤可以自动执行,但它们实际上是对生产力的打击,没有任何实际收益。

如果Eclipse默认不进行类导入,那么每个人仍将进行星型导入。很抱歉,但是确实没有合理的理由来进行特定的进口。

以下是处理类冲突的方法:

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在java.util中添加了一个名为List的接口。繁荣!冲突。完美工作的代码不再起作用。

这是一种EVIL语言功能。没有理由仅仅因为将类型添加到包中而停止编译代码了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

另外,这使读者很难确定我们正在使用哪个" Foo"。

在先前的项目中,我发现从* -imports更改为特定的import可以将编译时间减少一半(从大约10分钟到大约5分钟)。 * -import使编译器在列出的每个软件包中搜索与我们所使用的软件包相匹配的类。尽管这段时间可能很小,但对于大型项目而言却是加总的。

  • -import的副作用是,开发人员将复制并粘贴常见的导入行,而不用考虑他们的需求。

在Java import语句中使用通配符也不错。

在Clean Code中,Robert C. Martin实际上建议使用它们来避免冗长的导入列表。

这是建议:

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.