开发者

Eclipse/Java - is it harmful to import java.(namespace).*?

Why does Eclipse take a fine grained approach when importing types? 开发者_运维技巧 In C# I'm used to things like "using System.Windows.Controls" and being done with it, but Eclipse prefers to import each widget I reference individually (using the Ctrl+Shift+O shortcut). Is there any harm to importing an entire namespace if I know I'll need multiple types in it?


Eclipse has a great setting called the "Organize Imports" in the Window -> Preferences dialog that lets you say when N classes are used from a package, do a wildcard import. I use it at N=2 or 3 usually.


Somebody can read your code without IDE - in this case non-wildcard imports will help him to figure out which classes are used in your code.


The only harm that wildcard package imports can cause is an increased chance of namespace collisions if there are multiple classes of the same name in multiple packages.

Say for example, I want to program to use the ArrayList class of the Java Collections Framework in an AWT application that uses a List GUI component to display information. For the sake of an example, let's suppose we have the following:

// 'ArrayList' from java.util
ArrayList<String> strings = new ArrayList<String>();

// ...

// 'List' from java.awt
List listComponent = new List()

Now, in order to use the above, there would have to be an import for those two classes, minimally:

import java.awt.List;
import java.util.ArrayList;

Now, if we were to use a wildcard in the package import, we'd have the following.

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

However, now we will have a problem!

There is a java.awt.List class and a java.util.List, so referring to the List class would be ambiguous. One would have to refer to the List with a fully-qualified class name if we want to remove the ambiguity:

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

ArrayList<String> strings = new ArrayList<String>();

// ...

// 'List' from java.awt -- need to use a fully-qualified class name.
java.awt.List listComponent = new java.awt.List()

Therefore, there are cases where using a wildcard package import can lead to problems.


The import directive is a compiler directive, it tells the compiler where to look for a class and allows to not have to always use fully qualified class names, e.g. java.util.HashMap. But the import directives themselves do not get put into the compiled bytecode files, the compiler compiles the fully qualified name into the .class file.

When used wiithout a wildcard, the directive explicitly tells the compiler to look for one specific file in the classpath. With a wildcard, the directive tells the compiler to look for the named package and to search in that package for possible matches every time any name needs to be matched. The latter version is probably going to take (a bit) longer for the compiler than the former.

In other words, the import directive cannot affect runtime code execution in any way. However, the import directive does affect compilation time. Additionally, I find that using import with wildcards makes the code less readable.

Actually, the cost of import statements question of the month on javaperformancetuning.com perfectly summarize this in its conclusion:

  • There is no runtime cost from using an import statement
  • The compilation process can take a little more time with an import statement
  • The compilation process can take even more time with a wildcard import statement
  • For improved readability, wildcard import statements are bad practice for anything but throwaway classes
  • The compilation overhead of non-wildcard import statements are minor, but they give readability benefits so best practice is to use them


I don't believe that wildcard imports have any sort of performance implications (and if it does, I think it would only happen at compile time). But as this SO post points out, it's possible that you can have class name overlaps if you use them.

I just use Ctrl+Space to force the import when I'm using a class that hasn't been imported yet, and the import happens automatically. Then I hit Ctrl+Shift+O after I refactor a class to remove any imports that are no longer used.


Up until JDK 1.2 this code would compile fine:

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

public class Foo
{
    // List is java.awt.List
    private List list;
}

in JDK 1.2 java.util.List was added and the code no longer compiled because the compiler did not know which List was wanted (awt or util). You can fix it by adding "import java.awt.List;" at the end of the imports, but the point is you have to do something to fix it.

I personally use the single import instead of the on-demand import for two reasons:

  1. it is clear where each class comes from
  2. if you have a huge number of imports the class is probably doing too much and should be split up. It is a "code smell".


From a purist point of view, every import creates a dependency and a potential for conflict. Imports are treated as a necessary evil so they are minimized. Importing another package with a * is like writing a blank check. Importing two packages like that is like giving somebody access to moving money between your accounts.

From a practical point of view, this often makes sense because different projects and libraries use surprisingly similar names for differing concepts. Or, imagine you import everything from package A and then everything from package B, and use some class C from package B. If someone later on adds a class with the name C to package A, your code might break!

That being said, I admit I'm lazy. I'll often pre-import everything in the package, and then let Eclipse organize it for me based on what I actually use.


There's no harm in importing all the classes in a package/namespace, but I think it's better to include each individual class. It makes things clearer to developers who come after you exactly where each class comes from.

It's a non-issue if you're using a capable IDE like IntelliJ. I would imagine that Eclipse and NetBeans can manage imports as well. It will add the code for you and collapse them from view so they don't clutter the window. What could be easier?


Doesn't hurt the code. As a general principle, why import something if you are not going to use?


If you write some java code such as

LinkedList<foo> llist = new LinkedList<foo>()  

and you haven't imported LinkedList to your project, Eclipse will ask if you want to import it. Since you are only using LinkedList and nothing else, it will only import LinkedList. If you do something else in the same project such as
ArrayList<foo> alist = new ArrayList<foo>()

Then Eclipse will also say you need to import ArrayList, but nothing else. Eclipse only has you import what you need based on any library calls you have made. If you need multiple types or items from the same library, there isn't harm in using a

import java.namespace.*

to go ahead and bring in the other items you need. Eclipse won't care as long as you are importing the packages and libraries that contain the items you are referencing such as Scanners, LinkedLists, etc.

From a readability perspective, it's a different question. If you want people to explicitly know what exactly you are importing, then calling each widget or package might be in order. This can get rather tedious if you are using lots of different functions from the same package in the standard library and can make your file headers quite long hence the .* wildcard. There's no harm in importing via wildcard, it really boils down to your coding standards and how transparent you want your class headers to be.


Importing each class explicitly gives a hard binding between the short name (e.g. Proxy) and the long name (e.g. java.lang.reflect.Proxy), instead of the loose binding saying that there probably is one in java.lang.reflect.*, java.io.* or java.net.* or somewhere else of the wildcard imports you have.

This may be a problem if for some reason another class named Proxy shows up somewhere in java.io.* or java.net.* or your own code, as the compiler then doesn't know which Proxy class you want as it would have if you explicitly imported java.lang.reflect.Proxy.

The above example is not contrieved. The java.net.Proxy class was introduced in Java 5, and would have broken your code if it was written as hinted above. See the official Sun explanation of how to circumvent wildcard problems at http://java.sun.com/j2se/1.5.0/compatibility.html

(The wildcard import is just a convenience mechanism for those not using an IDE to maintain import statements. If you use an IDE then let it help you :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜