4

Consider I use a type X in my java compilation unit from package foo.bar and X is not defined in the compilation unit itself nor is it directly imported. How does a java compiler resolve X now efficiently? There are a few possibilities where X could reside:

  1. X might be imported via a star import a.b.*
  2. X might reside in the same package as the compilation unit
  3. X might be a language type, i.e. reside in java.lang

The problem I see is especially (2.). Since X might be a package-private type, it is not even required that X resides in a compilation unit that is named X.java. Thus, the compiler must look into all entries of the class path and search for any classes in a package foo.bar, it then must read every class that is in package foo.bar to check whether X is included.

That sounds very expensive. Especially when I compile only a single file, the compiler has to read dozens of class files only to find a type X. If I use a lot of star imports, this procedure has to be repeated for a lot of types (although class files won't be read twice, of course).

So is it advisable to import also types from the same package to speed up the compilation process? Or is there a faster method for resolving an unimported type X which I was not able to find?

gexicide
  • 38,535
  • 21
  • 92
  • 152
  • Your computer is fast. Finding the reference to the class won't take long. Plus Java libraries are probably cached to improve compilation times. Not sure though. – Anubian Noob Jun 06 '14 at 08:02
  • When you say "when I compile only a single file" You mean when I change a single `.java` file and then compile? – weston Jun 06 '14 at 08:10
  • I cannot believe this is a problem you need to worry about in this day and age. If this is a purely theoretical question, I'd stop worrying about it. If you find your performance is terrible, then tell us a bit more about that and maybe there's something we can do to help. – Duncan Jones Jun 06 '14 at 08:27
  • 1
    @Duncan: Well, java builds of larger projects happen to take quite some time. If adding imports for all classes in the same package could yield, e.g., 20% less compile time it would be worth adding those imports. Thus, the question is not purely theoretical. – gexicide Jun 06 '14 at 08:34
  • @gexicide Perhaps you should try some experiments? I'm still expecting it won't make any difference and that the large compilation times you see on big projects is unrelated. – Duncan Jones Jun 06 '14 at 08:48
  • @Duncan: Well I had to add a lot of imports into a large project to see any measurable difference (if there is any). That would take too much time, since it is indeed to be doubted whether it is useful. This is why I was asking here: Maybe there is someone with more in-depth knowledge that can give an educated guess whether it would be worth trying it. – gexicide Jun 06 '14 at 08:50
  • The process is completely defined in the JLS, not as to implementation, but as to the required steps in the required order. – user207421 Jun 06 '14 at 09:56
  • @EJP: I know, but the question is whether there is a clever implementation technique that would make this process cheapter than I expect it to be. – gexicide Jun 06 '14 at 10:04

2 Answers2

1

That sounds very expensive.

If the compiler did it that way, it would be expensive.

But what actually happens is that it builds an in-memory data structure containing all of the class names on the classpath, bootclasspath and sourcepath, and uses that for all of the classname resolutions in all classes that are compiled in the javac run.

So is it advisable to import also types from the same package to speed up the compilation process? Or is there a faster method for resolving an unimported type X which I was not able to find?

No, and no. It will make almost no difference. And besides, this is unlikely to be a significant bottleneck if you use the compiler how it was designed to be used.

It is better to do the imports in a way that gives the most readable and reliable code.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

Thus, the compiler must look into all entries of the class path and search for any classes in a package foo.bar

That's just Class.forName().

it then must read every class that is in package foo.bar to check whether X is included.

I don't know what this means.

After looking for a .class file via Class.forName(), it then has to look on the sourcepath in the current package for a file by the appropriate name, which is just new File(...).exists() etc.

I'm not convinced that it looks inside each file for non-public classes by that name: you would have to try it. If it does, that is indeed an expensive step, but I'm not convinced it's taken.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • The evidence would be in the compiler source code. But you can infer this from the fact that `forName` actually loads the class bytecodes and links them. The bytecode compiler doesn't need that, and it would be wasteful of both CPU and memory to do it. My understanding is that the compiler has its own classfile reader that only reads the symbol table information that the compiler needs. – Stephen C Jun 07 '14 at 03:26