First, I should qualify my statement above about the uselessness of cross platform. Some may recall that there was a cross platform language long before Java; it's called "C". At a time when you were considered insane for closing your source, C was a great cross platform language. However, Bill Gates and others of his ilk didn't see it that way.
With the recent surge of interest in Free Software, C can once again be the cross platform language it was meant to be. Sure, it means putting a few ugly #ifdef's in your code, but the result will be code which is actually better at being cross platform then the "write once, debug everywhere" of Java. Also, recompiling isn't as big a deal in Free Software as it is in closed-source. In any case, we don't need it, and anything in the language specification for having this functionality outside what is in normal C/C++ should be viewed as language bloat.
In short, Free Software only cares about the source being cross platform, not the binaries.
This brings me to my first point: #ifdef. It makes sense in theory to not have something like an #ifdef in Java, given Sun's goals for the language. However, real life isn't so kind, and our goals are somewhat different from Sun's, right? There are some Java compilers (especially machine-code compilers; more on that later) that have problems with certain code tricks, libraries, etc. Using something similar to an #ifdef could often fix this problem, but Java has been neutered of this ability (some have suggested patching the code during the 'make' process if a specific compiler was used, which is very kludgey, to say the least). Besides, adding this doesn't really make it any worse then C/C++, it's just adding functionality they already have.
An #ifdef may help non-Free Software, but not as much, since non-Free Software has the advantage that it probably knows what compiler will be used ahead of time and can thus not use tricks that that specific compiler can't handle. Note that this differs from coding your program specifically for a compiler (which is bad programming practice, except in rare circumstances) in that we are not programming it to optimize for that compiler, just working around its bugs. Free Software usually doesn't have that luxury, and could thus benefit more from an #ifdef-alike.
The second point, is various deficiencies in keywords, although these are certainly not specific to Free Software. Inline could help a lot in speeding up programs, as could macros. Several times I find myself wanting to use a macro (another thing I'd like to see added) or inline function but must put up with using a function call. Java does do some automatic inlineing for you, but frankly, I prefer to have more control over what the compiler does.
I really want to see an unsigned keyword, so much so that I wrote GPL'd UnsignInt and UnsignShort libraries myself (and kludgy ones at that!). I'd still like to see this become a keyword, though.
A const keyword would also be nice, as it adds to self-documenting code, as this post brings out.
Thirdly, there's various issues with libraries in Java, but again, these are hardly specific to Free Software. Those who have programmed in Java know just how ugly the various file I/O libraries are. To read a file, you want to use
java.io.BufferedReader (just as an example). But wait! The constructor for
BufferedReader takes in a
java.io.Reader object. Actually, you probably don't want to use
Reader directly, but rather a class that extends it, probably
java.io.FileInputStream. Phew! To summarize this into code:
// "filename" is a String declared elsewhere
BufferedReader in = new BufferedReader(new FileInputStream(filename));
OTOH, this process does allow a lot of flexibility, but I'd really like to see a library that wraps this whole process into one class. In Java's defense, it would be quite easy to write this wrapper yourself.
String manipulation is also severely lacking. The library
java.util.StringTokenizer are about all you get.
StringBuffer allows you to append or prepend a String, or put data in an arbitrary location into the String.
StringTokenizer lets you break a String into smaller Strings at a certain delimiter character. We might not need it to be as great as perl, but could we have something a little heftier, please?
There has been a lot of talk of licensing issues. Depending on how strictly you interpret the GPL, it may be illegal to use a GPL'd program on a non-Free VM, unless you say that the VM is an OS of sorts. This can be solved by either using a Free VM (like Kaffe), using a machine code compiler (see bellow), or by appending your program's licensing statement with something like this:
This program is distributed under the terms of the GNU General Public License, with the extension that it may be used on a non-Free Java Virtual Machine.
Of course, IANAL, so much will have to be done to make sure this statement is legally binding.
Lastly, Java byte code. Like the lack of #ifdef, using interpreted byte code makes theoretical sense given Sun's commitment to making Java cross platform. It also makes sense on embedded devices. However, for desktops, byte code is just a resource pig. While JIT compilers help this a lot, it would be better just to go straight into machine code. Fortunately, the GNU project is creating just such a compiler that is part of the GCC suite. It's called GCJ, but it is extremely buggy right now.
There are other machine code compilers, such as Visual J++, but none that are Free Software. Getting your program to compile on GCJ is somewhat like eating steak with a spoon. This is unfortunate, given the speed and memory use you can see over plain old byte code, even with a JIT compiler (which incurs some overhead in converting the byte code to machine code on the fly). Given time, GCJ will fix it's bugs and can become widely accepted throughout the Free Software community, but until then, a resource-hogging byte code compiler (preferably JIT) is generally the most sensible alternative.
In summary, my suggestions are to add something similar to an #ifdef, additions of inline, unsigned, and const keywords, clean up the libraries while leaving the current flexibility intact, and greater use of machine code compilers. These recommendations, I feel, will make Java far more suitable for use in Free Software.