I really like java as a language, but the behavior of the compiler can be a pain in the ass to deal with.
The problem with javac, is that it does some stuff that is akin to what make does. It figures out dependencies and compiles them for you. It tries to understand your source structure and resolves external classes at compile time. which in many ways is really handy, as it can typecheck against other classes without the need for header files.
But here’s where it get’s really annoying. If you try to work javac into a build system written in something like make or scons, it can get downright impossible. The problem is that given a .java file, it’s not easy to figure out which .class files get generated. Even if you could parse the file and find all the inner and anonymous classes, you still wouldn’t know which other files javac will go and build for you when you specify it to only build. For example, say you had the files:
a.java b.java c.java
and @a.java@ looked like:
import b; import c;
If you were to tell javac to compile @a.java@, it would go and build @b.java@ and @c.java@ for you. So not only do you have to parse the local code of a.java, you have to understand how javac finds other classes, and also how this behavior is controlled by the comand line options.
For small projects @javac *.java@ may work just fine, but when it comes to huge automated build scripts, it can be a tricky thing to deal with.