There are many reasons to hate Java, it's like shooting fish in a barrel. But in the last weeks I found some more, half of them aren't even fault of the standard API (the usual culprit), and I want to share my frustration with the rest of the world.
It has no unsigned types
Say you want to manage binary protocols, files, etc. You'd like to store and retrieve bytes and words in machine format, of course, but you'll have a hard time finding the right value because you can't have a goddamn unsigned byte!
So if you want —for example— to read the length of a string which can be bigger than 127 as a single byte, you'll end doing some aberration like this:
byte strl = foo_retrieve_byte();
int real_strl = strl < 0 ? 256 + strl : strl;
You can't inherit constructors
Maybe there's something in the OOP dogma that mandates this, but if I want to define a new exception that does nothing, but allows me to differentiate a custom class of errors, I don't want to explicitly write dummy constructors instead of writing an empty class —which is simpler and cleaner— and have the four standard exception constructors for free. So, you'll have to do this:
public class FooException extends BarException {
public FooException() { super(); }
public FooException(String s) { super(s); }
public FooException(Throwable t) { super(t); }
public FooException(String s, Throwable t) { super(s, t); }
}
Instead of this:
public class FooException extends BarException { }
You can't declare destructors
Say you've coded a nifty jdbc wrapper that automates most of the boring stuff, like automatically freeing the connection to the connection pool when there was an exception thrown, logs errors and maybe queries, handles auto-commit settings, etc. In the simple case, you'd create an instance, do some work, and then close the connection; if there was an SQL exception, you little class will take care of it and re-throw.
BUT, if in the middle of your work in the calling code, you have an unrelated exception, you need to catch it or you'll leak connections, because the wrapper class doesn't have a way of handling this, even if the object gets garbage collected! In the end, I had to write tons of times the same stupid code:
try {
j = JdbcWrapper.new(foo);
j.doSelect(bar);
unrelatedObject.unrelatedMethod();
j.doUpdate(baz);
} finally {
j.close();
}
You don't have a sane way of controlling the terminal
Most of the time, when dealing with web applications, you won't need this. But when you're doing some serious stuff, you might need to write a CLI application (oh, noes!); and then do some stupid thing like asking the console to stop echoing characters so you can ask for a password. You'd think that the smart guys that designed Java would have devised an portable library to handle this trivial task, but no! Guess what I found when looking at a way of doing this? Some idiot at SUN recommending (and many dummies following) a background thread that spits backspaces faster than the user can write!
Of course, SUN will tell you that using Strings is insecure for storing passwords, because they cannot be wiped out like byte arrays. But they fail to mention something as basic as not showing the fucking password in the first place, or something as important as wiping the object after using it: you can't lock memory from Java, so you risk that it could end in some slack in the swap file.
No, you can't leave stdin/stdout/stderr fscking alone!
When dealing with the previous problem, you say fuck portability and just
call stty -echo
to do the job. Well, you'll find a little
surprise!
Even if you don't ask for the process' reader/writer streams, the Runtime class will pipe(2) and dup(2) your child process' standard streams. With this excellent approach you cannot have a child process output stuff to the user, nor even errors; you cannot allow the child process access the tty (stty obviously can't do shit with a piped stdin). And there's no fucking way to tell it to stop crippling your standard streams!
The only solution I could find was a very ugly shell hack:
Process p = Runtime.getRuntime().exec(
new String[]{"sh", "-c", "stty echo > /dev/tty < /dev/tty 2>&1"}
);
No, you can't handle signals
After doing the previous hack, you find that if you interrupt your process
while waiting for user input, your console will remain in noecho
state. So the obvious thing is to catch SIGINT
and friends and
call stty again to restore the console. HA! You will find that there's no
standard way of doing that, and if you really need it, you have to resort to
undocumented com.sun.*
classes which aren't even guaranteed to be
present in every JVM.
My solution was to set up a shutdown hook, which solved this problem, but would not solve other very common problems that are solved usually with signal handlers.