How can I prevent Eclipse from importing nested classes? - java

Whenever I use nested classes, I give them names not including the outer class name, e.g.,
MySomething.Kind and not MySomething.MySomethingKind. The nested classes are sometimes visible to the outside and then I want to refer to them always by the name qualified by the enclosing class, i.e., MySomething.Kind and not just Kind. Sometimes there are multiple classes containing a nested Kind, so using the unqualified name may be confusing.
Is there any way to prevent Eclipse from needlessly importing mypackage.MySomething.Kind instead of using (already imported) mypackage.MySomething together with the semi-qualified name?
UPDATE:
This doesn't happen spontaneously. As stated by jprete, when I always use the semi-qualified name, the nested class doesn't get imported. But any refactoring creating a variable of type MySomething.Kind declares it as Kind only and adds the unwanted import statement. This turns the refactoring to useless, as I have to edit it manually. Whenever I forget, I get the worst of both: a mixture of unqualified and semi-qualified names.

I have found that, if I always refer to the nested class with the "semi-qualified" name - i.e. MySomething.Kind rather than Kind - that Eclipse will not try to automatically add import mypackage.MySomething.Kind when I tell it to reorganize imports, but instead will only add import mypackage.MySomething and leave the "Class.NestedClass" references alone.

It looks like there's no solution, but what I'm doing now is pretty practical (when used in a script):
find src -name "*.java" | xargs perl -pi -e \
's/^(import [.\w]+\.)([A-Z]\w+)(\..*);/$1$2;/;'
It simply replaces all the unwanted imports like
import java.util.Map.Entry;
by the outer class imports like
import java.util.Map;
It's matter of seconds to fix the errors manually and let organize imports get rid of duplicates. It ignores static imports as I want.
Warnings:
it touches all files (solution)
you have to refresh them in eclipse
it modifies the source code, which is something nobody should do without a source control

Related

Why should the Java compiler not support inheritance of imports?

In Java, imports are related to an (outer) class, as every (outer) class is supposed to be coded in a separate file. Thus, one could claim that the import ...; directives before a class definition are associated with the class (somewhat like annotations are).
Now, if one could inherit a parent class' imports, that would greatly reduce the clutter of source files. Why should this not be possible? i.e. why should the Java compiler not consider also the imports of base classes?
Notes:
There's probably more than one answer.
I know this is not much of an issue if you let eclipse organize your imports, no need to mention that. This is about the 'why', not the 'how' (a-la-this).
Firstly, it is important to note that not every class must be coded in a separate file - but rather that every public, top level class must be. And no, imports are not really associated with any class - they are just statements used to include certain external classes / packages within a file so that they can be used. In fact, you never need to actually import anything, you can always use the full name, i.e.:
java.util.List<String> list = new java.util.ArrayList<String>();
Imports are there for convenience (and only for the compiler - they are lost after the class is compiled), to save you from having to write all that out and instead only make you write List<String> list = new ArrayList<String> (after you make the relevant imports from java.util). Consequently, there is no reason why subclasses should 'inherit' imports.
Imports are syntactic sugar, nothing more. You could write any Java program without ever using an import statement if you really wanted to. For example, the following class compiles all by itself:
class Foo {
java.util.List<String> list = new java.util.ArrayList<String>();
}
Additionally, inheriting imports makes it much, much harder to remove an import from a class. For example, if Bar.java inherits from Foo.java, you might not be able to remove an import from Foo without adding it to Bar. Forcing imports to be explicit makes it significantly easier to change a single file without worrying about the effects on other files, which is pretty much a fundamental principle of Java and object-oriented programming generally.
(This last point is related to issues that were a significant factor in the design of Go, which was specifically attempting to avoid the problems with C and C++ in this area.)
Having each file explicitly specify its imports improves readability. Imagine opening a file and not being able to see the dependencies at a glance, because the imports are inherited from another file.

Import Java classes once for all package

Let's say, I have the following structure:
src.main.java
first
one.java
two.java
three.java
second
alpha.java
beta.java
gamma.java
I want all classes from first package to be imported in all classes in my second package.
Now I'm just specifying for every class in second package:
import first.*;
Can I import once for all classes in package?
No, it cannot be done.
I don't see why this is such a hardship.
A better solution would be to use an IDE that can add the imports as you need them.
I'd also recommend spelling each one out individually rather than using the star notation, even if you need to import all of them. It documents your intent better, and that IDE can make it transparent to you.
No, you can't do that in Java.
One thing that you might think of doing is moving classes from second package to first so you won't need the imports. But I understand that that is not always possible/desirable.
Can I import once for all classes in package?
No you can't. Imports only apply to the class source file in which they are declared.
Maybe I can create some superclass with import statements and then extend it every time?
That will only work if the code in the subclasses does not mention the names of the external types at all ... which is rarely possible.
As I said imports only apply to the class source file in which they are declared.
Actually, the import was deliberately designed to work this way. The idea is to allow you to easily figure out what class a classname refers to. (It works best if you don't use star imports ...)

Java class name same as the nested package name

In my Java application, I use a third-party library.
However, I found something strange, there are some nested packages, and some classes whose name may be the same as the name of the package.
I am afraid I can not make it clear. Here is an example:
package
com.xx.a
com.xx.a.a
And there is a class named 'a' inside the 'com.xx.a'.
So if I want to call this class 'a'...
I write:
a ma = new com.xx.a.a();
Then the IDE will think that I mean the package 'com.xx.a.a'.
Then I can not call it.
I wonder why?
By the way, it seems that the library provider did not want us to use these kinds of classes.
How do they do this?
The Java language allows class identifiers to be obscured by package identifiers. In your case the class com.xx.a is obscured by the package com.xx.a.
From the Java Language Specification:
6.3.2 Obscured Declarations
A simple name may occur in contexts where it may potentially be interpreted as the name of a variable, a type or a package. In these situations, the rules of §6.5 specify that a variable will be chosen in preference to a type, and that a type will be chosen in preference to a package. Thus, it may sometimes be impossible to refer to a visible type or package declaration via its simple name. We say that such a declaration is obscured.
I must say that the rules in §6.5 for classifying the meaning of an identifier are far from clear though.
The reason why you still happen to have a copy of a library that violates this rule is because the rule does not apply for class files / JAR files and the JVM.
This means that you can have such naming conflicts in JAR files, but you'll never see it as output from javac. The tool that has produced these class / package names is most likely a code obfuscator which produces this kind of messy code to compress the size of the files and to obfuscate the code to prevent reverse engineering.
PS. At a closer look it may actually be a bug on the Eclipse side (assuming that's the IDE you're talking about). By letting an empty package name collide with a class name, Eclipse chokes on something javac accepts. The spec is hard to follow, but from what I can see, javac follows the spec in this case.
This is a common issue when decompiling jars.
The Compiler will get confused when there is a class and a subpackage with the same name. If you don't find a compiler with the option to append a prefix regarding the type(package, class variable) you have to refactor the source files. You can do that with regex by for example renaming every package declaration and import from
import A.B.C
to something like
import pkgA.pkgB.C.
Of course you can't do that for the external packages from the sdk or other libraries but most of the time the used obfuscator renames them in the same way so for renaming to letters from A-Z you could use something like:
RegexFindAll("import\s+(?:[A-Z]\s&ast;.\s&ast;)&ast;([A-Z])\s&ast;.\s&ast;(?:[A-Z]\s&ast;.\s&ast;)&ast;[A-Z]\s&ast;;")
RegexFindAll("package\s+(?:([A-Z])\s&ast;.\s&ast;)&ast;([A-Z])\s&ast;;")
And from there on you can rename every package. If your IDE doesn't offer such functionality you can also rely on the terminal with following commands.
To find all the files by name recursively(extendable with filename filter)
find -follow from https://stackoverflow.com/a/105249/4560817
To iterate over the found filenames
sudo find . -name *.mp3 |
while read filename
do
echo "$filename" # ... or any other command using $filename
done
from https://stackoverflow.com/a/9391044/4560817
To replace text inside a file with regex
sed -i 's/original/new/g' file.txt from https://askubuntu.com/a/20416
You need to do this:
com.xx.a.a ma = new com.xx.a.a();
Or import the package:
import com.xx.a;
a ma = new a();
The library is likely obfuscated (e.g. using proguard) to reduce size, prevent reverse engineering and "hide" stuff you're not supposed to use. Even if you manage to create an instance of this class, I would recommend against it, as you don't know what it will do or how it can/should be used.
we can not do this in java:
com.xx.A
com.xx.A.yy
the package name clashes with a class in the parent package,.

Could extra imports in Java slow down code loading time?

Is it possible that adding more import statements to your java code could slow down the time it takes to load your classes into the JVM?
No, imports are only used in compilation to find class references. Add unused imports and they don't do anything. To put it another way:
import java.util.*;
simply means you can write:
Map map = new HashMap();
instead of:
java.util.Map map = new java.util.HashMap();
That's all it does.
No. Imports are purely a compile time construct ... syntactic sugar.
The imports tell the Java compiler how to map identifiers in the source code to fully qualified class names. But if the source code does not use an imported class, the bytecode file will have no references to it. Hence, a redundant import does not (and cannot) impact on class load times.
Imports can have an effect on compilation time, but not on loading time or running time. Basically, if you import classes that you don't need (typically by using wildcard imports when explicit imports would do), then you can slow the compiler a bit.
However, even that effect is generally trivial unless you are compiling a huge system.
Don't confuse the word "import" with "class loading". The import statement does not cause any code to be loaded into memory. It's just a convenience that allows you to refer to classes using their short name instead of typing the full class name (e.g, "Connection" instead of "java.sql.Connection").

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:
it is clear where each class comes
from
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 :)

Categories