(It was obvious.)
-
Many common tasks take an absurd amount of code. For example, try producing a date in RFC2822 format, in the local time zone. Isn’t Java supposed to be a good language for Internet programming?
-
What’s with the special types that aren’t objects, like int? I just want to have integers, and leave the compiler to determine the appropriate implementation. In the worst case, I don’t mind specifying how wide I want my integers in advance, but please, can we have them act like proper objects (i.e. everything else)?
I mean, it’s not like anyone is going to be using Java for systems programming, and need access to raw machine words, especially since there are no unsigned integer types available. (Bytes are signed?!)
In Java 1.5 they try to make it less ugly by having the compiler automatically wrap primitive types in object wrappers when necessary. Which is still ugly.
-
Why must arrays be unlike every other type? For instance, array objects use variable.size() to find out their upper bounds, but arrays use variable.length. They’re not like the other special types either, because they can’t be converted.
-
Clearly very little thought has been put into doing things right the first time. That makes for a horribly bloated and messy API. So we have arrays, Array objects, ArrayList objects, and Vector objects, all solving the same problem in subtly different and incompatible ways. Ditto Hashtable and HashMap.
-
No integer overflow detection. For a language designed to be safe that forces me to pick a size of integer in advance, that’s pretty stupid.
-
The class library is riddled with little inconsistencies that make it difficult to remember how to use everyday objects. For instance, “HashMap” is camel-cased, but “Hashtable” isn’t–and of course, fussy Java will complain if you capitalize even slightly differently.
-
No abstract local functions. I happen to find map operations very useful at times.
-
Some arguments are passed by value, some are passed by reference; it depends on their type.
-
Similarly, the types that would be passed by value are copied during assignments, the types passed by reference are not. Hence, assuming you remember something has been passed in by reference and want to copy it, you specifically have to clone() it to make a copy–and if it’s in an array, you have to clone the dimensions of the array manually.
-
Comparing pass-by-reference variables checks if they’re references to the same thing, rather than checking if they’re the same value. To check if they’re the same value, you have to remember that they’re ’special’ and that you have to use .equals() instead of ==. Except it doesn’t work on arrays. D’ohh!
-
Constructors have their own special unique syntax. The compiler spots immediately if I don’t use the special syntax, therefore it clearly knows that the method is the constructor anyway, therefore it’s just arbitrarily making me jump through hoops for it.
-
Importing packages doesn’t import dependencies. For instance, org.xml.sax.XMLReader is no use without org.xml.sax.helpers.XMLReaderFactory, so why make me import them separately?
-
There’s no way to break string literals across lines, so you have to concatenate them at run time.
-
Some of the documentation is really awful. I mean, does anyone understand RuleBasedCollator? Quote: “& Indicates that the next rule follows the position to where the reset text-argument would be sorted”. Is that even English?
There’s also an unfortunate tendency for people to assume that JavaDoc is documentation. Often, it’s more like an adventure game, where you click around in a maze of twisty turny JavaDoc pages for hundreds of classes, hoping that at some point you’ll find some documentation that actually tells you how to perform some task you need to perform, rather than just telling you what lots of random methods do.
-
Startup times are abysmal.
-
Exceptions are a pain. The ability to throw and catch exceptions is a good thing in any language; the problem with Java is the insistence that every exception be explicitly dealt with or thrown up the chain.
In J2EE code, for example, we have the SQLException. It either indicates a syntactic error in the SQL code, or that the connection to the database is broken. There’s really nothing the application can usefully do with SQLException except report an error and die; yet because of the explicit exception rules in Java, code ends up bloated with repeated catching and rethrowing of SQLExceptions.
It’s not clear to me that forced exceptions do anything to make programmers deal with possible problems anyway; try running Azureus and watch how many stack traces it craps to the console. Good programmers don’t need to be force-fed exceptions, and bad programmers just catch and ignore the exceptions anyway.
The other side of the problem: if you’re implementing an interface that doesn’t declare any exceptions, you have to eat any exceptions that occur, no matter how deadly.
I’m not sure what the solution is, but with Java I get the feeling that the cure being tried is of marginal effectiveness, and possibly worse than the disease.
-
Generics were added too late. Now we’ve got a massive class library full of unnecessarily ugly APIs.
-
String and StringBuffer make straightforward string handling unnecessarily painful. You can split a string, but you can’t modify it. You can find a string within a StringBuffer, but only in case-sensitive fashion. You can’t search a StringBuffer for a regular expression; you have to convert it to a String first–but to modify what you find, you have to convert back to a StringBuffer again, or create a new String (and pay the cleanup costs).
So in typical input parsing, you end up repeatedly converting between String and StringBuffer objects. Even assuming that’s what the compiler would have to do anyway, why should I be forced to do it all explicitly? And if “replace string” is only available for StringBuffer, how come “replace regexp” is available for String? The whole division between the two has long ceased to make any sense.
-
In Java, null is a primitive value. But, as mentioned above, primitives like ints aren’t objects, and so neither is null. Which, in turn, means you can’t use null for null objects (for example when making objects optional)–you need to clutter the API with more methods, create empty objects, or implement a null object class.
-
IO is ugly. To do the normal “buffered write to a file”, you have to create a FileWriter object, wrap it in a BufferedWriter object to add buffering, then wrap that in a PrintWriter object to get a stream you can print to. That is:
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(new File(filename))));And don’t forget to explicitly flush and close the PrintWriter, or you’ll lose data. So much for safety! Input is just as bad. Is it too much to ask that the 90% of cases (stream-based reading and writing of text) be optimized with some kind of 1-step BufferedPrintToFileFlushOnDispose class?
-
I find the use of “static” to indicate “class scope” unnecessarily confusing. To put it another way, I find it hard to remember that “final” means “static” (unchanging) and “static” means “class”…
Of course, the reason why “static” is used for class methods is that Java doesn’t really have class methods; static methods are static in the sense that they’re really global functions that can’t be overridden and are shared between all objects of that class. Perhaps the word “shared” would have been less confusing?
-
The insistance on a separate file for each class fragments the source code and makes it harder to keep track of where things are–or alternately, encourages the “one huge class” antipattern. The insistence on making the directory structure match the package naming adds the annoyance of having to navigate in and out of directories multiple layers deep even for a trivial project.
Things I really like about Java
- Unicode everywhere, no special effort required.
- It’s pretty much portable between Linux and OS X, without having to worry about contortions like autoconf.
I don’t include automatic memory management in the list, because that ought to be a given for any modern programming language.
I should also point out that for all its faults, Java is still better than C++.
The Eclipse project has developed a toolkit which allows you to write Java applications via an application toolkit called JFace. This in turn uses a toolkit called SWT to provide native user interface objects to your Java program. End result: native look and feel, faster applications.
So, if you’re a software developer, go take a look at the Eclipse web site. See if you can spot what’s missing.
Hint: It’s something incredibly important. So important that it ought to be on the main navigator. Yet incredibly, it isn’t.
OK, I’ll tell you what’s missing from the Eclipse project.
There’s no fucking documentation.
Sure, there are a bunch of articles they link to. But an article in Java Programmer Monthly does not constitute an API reference manual.
Nor do the crappy comments extracted from the source code via JavaDoc. Yet as far as I can tell, that’s all the documentation that exists for the entire project inside or outside IBM.
Yes, there are third party books, or at least there will be soon. But third party books aren’t a good substitute for actual documentation either, because (a) they’re usually out of date by the time they’re printed, (b) they’re often written by someone with appalling programming habits, and (c) in this case the authors of the books are likely having to guess what the hell the code does as well.
Lack of documentation is a defect. It indicates crappy development practices. Any time someone suggests that you use a particular toolkit, ask to see the documentation. If it isn’t clear and well-indexed, run like hell in the other direction, because it’s a fairly safe bet the code will be even worse. (Hello, Struts.)
I’ve just successfully written an EJB, deployed it, and called it from a servlet and some JSP.
Right now, it looks like the EJB specification has the highest complexity-to-benefit ratio I’ve ever encountered in a programming API. Sure, I’m a beginner to J2EE, but I’m an experienced software developer, and over the years I’ve developed an intuitive ability to recognize a pile of steaming crap when I see one.
Today I decided that writing my own application deployment descriptors was unnecessary drudgery, so I tried out xdoclet. It doesn’t work, I get various stupid error messages that I see (from the mailing list) have been reported by other people too. I strongly suspect crapulence on xdoclet’s part, since its API changed between release 1.1 and 1.2, and will change again completely for 2.0, which is a complete rewrite. (A lot of Java projects are like this.)
Oh well. Maybe one day they’ll integrate the functionality into ant where it belongs.
Spent the afternoon and early evening improving the screensaver and learning my way around Cocoa better. (As opposed to cocoa butter, which would probably have been much more enjoyable if used appropriately.) I now have a preferences sheet with various sliders and a color selector, and code to load and save preferences in the correct way. In the process, I triggered yet another bug; tracking it down revealed yet another way in which the reality of the screensaver API differs from the documentation. This in turn has suggested a possible cause for the “textures vanishing when returning from full screen preview” bug, which I’ll investigate tomorrow.
Also on the agenda for tomorrow is gluing together the parameters set by the preferences dialog, and the actual OpenGL snowflake animation code. Should be reasonably trivial, and while I’m in there I plan to try adding a couple more snowflake textures.
Once all that works, it’ll be 1.1b1. (1.0 was the same as 1.0rc2, for those who are keeping track, but I’m not going to bother making a separate renamed release.) Assuming 1.1b1 works for everyone else, I’ll probably go straight to 1.1 and announce it on MacUpdate and VersionTracker.
Anyway, by 19:00 my brain was shutting down from excessive programming. I was unable to engage in conversation; in fact, I was pretty much unable to engage with the outside world at all. I wonder if I was always like this when I was hacking code all day back in the early 90s? Probably, unfortunately. I suspect that being a highly productive programmer requires a state of mind which isn’t altogether healthy.
We went to the Rosebud, I ate fish since my body was craving it. (Listen to the body, sometimes it knows what it needs and will tell you.) I made a swift return to the human race. We came back, and with the aid of coffee I fixed the aforementioned bug. I rewarded myself with a couple of mince pies and a movie.
One of the disadvantages of NetFlix is that months can elapse between adding a DVD to your queue, and actually watching that DVD. So I know that somebody, somewhere recommended that I watch Gun Shy, but I no longer have any idea who. Anyhow, it was moderately funny, but a bit too tense to be completely enjoyable. I’d probably give it 3/5.
Last night I dreamed about work. It wasn’t even an interesting dream about work; I just dreamed about tradeoffs in API design for Java class libraries.
It was practically unpaid overtime. I’d try to claim for it, but they’d probably just dream that they paid me.
The following are extracts from transcripts of two tape-recorded conversations between undercover investigators from the Office of Special Investigations at the US General Accounting Office and two gun dealers in Nebraska and Oregon, respectively. The calls were part of an investigation by the House Committee on Government Reform into the availability of long-range .50-caliber sniper rifles and armor-piercing ammunition. With an effective range of four miles an the ability to pierce several inches of steel, .50-caliber rifles are among the most powerful and destructive firearms legally available in the United States. The rifles were widely used by US infantrymen in the Gulf War to penetrate armored personnel carriers and concrete bunkers. Convited felons and children under eighteen are not allowed to buy the ammunition or new rifles, though secondhand sales of the rifles are not regulated.
Agent:
Yes, I’m looking to see if you carry .50-caliber BMG armor-piercing incendiary.
Dealer:
A guy just bought the last thousand rounds about twenty minutes ago. I will have more back in here Monday or Tuesday.
Agent:
Okay. How much is it a round?
Dealer:
Two hundred and forty dollars a hundred.
Agent:
This ammo will go through, say, metal, won’t it?
Dealer:
Uh, yeah, it’ll go through metal.
Agent:
Okay. Do you think it would go through, like, an armored limousine?
Dealer:
Well, I think it would. [Laughing]
Agent:
How ’bout bulletproof glass?
Dealer:
Oh, yeah, it’ll go through that.
Agent:
Even if it’s ballistic glass, it’ll still go through?
Dealer:
Right.
Agent:
With the first round, probably?
Dealer:
Right.
Agent:
Okay. Now, I live on the East oast — can you send it to me?
Dealer:
Uh, whereabouts do you live?
Agent:
Uh, I live in Virginia, but I’d like it shipped to D.C.
Dealer:
Okay.
Agent:
How can I go about doing that?
Dealer:
I’ll put my assistant on, and she can give you all the information.
Agent:
Okay, but I’ve got a couple of technical questions first. This ammunition, does it clog up the barrel of the weapon?
Dealer:
Oh no—it’s got the soft jacket on the outside. We also have a sniper round we do for the government. What kind of gun are you shooting?
Agent:
A Barrett Model 82.
Dealer:
We’ve got a round we’ve developed for the Barrett, a solid-brass bullet with a poly coating on it—that’s our sniper round.
Agent:
And that’s what you’ve sold the government?
Dealer:
Yes.
Agent:
Now, that sniper round, does that give you higher velocity, greater distance, or what?
Dealer:
It gives you the best accuracy.
Agent:
So if I wanted to use this against a person, let’s say, the sniper round would be better?
Dealer:
Right, right, because it makes the rifle real accurate.
Agent:
If I got the sniper round instead of the armor-piercing incendiary, though, would it still go through ballistic glass?
Dealer:
Oh, I don’t know—I don’t think we’ve tested on ballistic glass. It’ll go through three-inch aircraft window.
Agent:
But, say, an armored limousine?
Dealer:
Uh, we’ve never tested it on that.
Agent:
All right. What’s the price for these sniper rounds?
Dealer:
Four dollars a round by the hundred, or fifty a round by the ten-round.
Agent:
So they’re more than the API?
Dealer
Oh yeah.
Agent:
Well, I think I’m better off with API. I’m going to be using this against, um, you know, something with an armored limousine and something with ballistic glass, and I just want to make sure I’m going to be able to penetrate. So put me on with your assistant there, and maybe I can figure out how I can get this shipped to me.
Dealer:
Okay, hold on.
Assistant:
Okay. What we’ll need is a copy of your driver’s license to prove that we’re shipping to someone over the age of twenty-one.
Agent:
Okay.
Assistant:
And a statement that you are over the age of twenty-one and that there are no federal, state, or local laws that prohibit you from receiving the ammunition. Once we have that on file, you’d never have to do it again — that’s just, you know, for the first time.
Agent:
Okay. So I just have to write a statement out and sign it, saying that I’m over twenty-one years of age and there’s no federal, state or local laws prohibiting me from –
Assistant:
Receiving the information.
Agent:
Ammunition, you mean.
Assistant:
And, uh, this can be faxed to us. Once we have it on file, we can send some stuff to you.
Agent:
Okay.
Assistant:
Can I get your name?
Agent:
My first name is Roger.
Assistant:
Okay.
Agent:
Well, actually, that’s just what they call me. My real name is Julian.
Assistant:
Okay.
Agent:
You can see why I want to be called Roger?
Assistant:
There you go. [Laughter] Okay.
Dealer:
Can I help you?
Agent:
Yes, I’m interested in ordering some .50-caliber BMG ammo. I was wondering if you have any in stock.
Dealer:
No, it’s all sold. I’m taking orders for a month from now.
Agent:
I may be interested in some API.
Dealer:
Okay.
Agent:
Now, do you know a lot about these rounds?
Dealer:
Well, um, some.
Agent:
Do you think they’ll go through bullet-proof glass?
Dealer:
Well, they’re loaded with the bullet weight the military uses now—660 or something.
Agent:
Uh-huh.
Dealer:
In the old days they used 700 grains or something. But nowadays they use 660, so they’re getting a little more velocity out of it. And I just can’t see glass standing up to that.
Agent:
How about an armored limousine?
Dealer:
You’re using that to test it?
Agent:
Well, you say testing—Yeah, I’ll be testing against armored limousines. But it’s gotta work.
Dealer:
Right.
Agent:
You know, I don’t want to have the chance of it not working.
Dealer:
Well, there’s no way that I can guarantee it. I’m not familiar with the glass they’re using nowadays.
Agent:
But you’ve never had any complaints from your customers about these being misfires or anything? These rounds are pretty good?
Dealer:
They’ll bore through a fair amount of steel.
Agent:
Okay.
Dealer:
I don’t know how strong the glass is, but the ammo will go through a fair amount of steel. [Laughing] It’ll go through the whole car.
Agent:
Okay. Would it go through a lightly armored tank, do you think?
Dealer:
It won’t go through any modern tank, because we have too much armor on them now.
Agent:
Uh-huh.
Dealer:
But it would probably go through two and a half or three inches of mild steel.
Agent:
Oh. An armored limousine definitely doesn’t have that much on it.
Dealer:
That’s what I’m saying. I think a .50 would go all the way through it.
Agent:
Okay. And then, if I theoretically wanted to use these rounds to take down an aircraft—say, a helicopter, or something like that—I should be able to do that, shouldn’t I?
Dealer:
Yeah, they’re not armored. I’ll go through any light stuff like that.
Agent:
Good. You know, I’m very happy to see that we’ll be able to do business. Here on the East Coast, when you go to buy ammunition, they ask a lot of questions.
Dealer:
Oh.
Agent:
And I don’t like people asking me questions about why I want this ammunition.
Dealer:
Well, see, out here they use it for hunting.
Agent:
Uh-huh. Well, you could say I’m going to be using this for hunting also. But just hunting of a different kind.
Dealer:
[Laughing] As long as it’s nothing illegal.
Agent:
Well, I wouldn’t consider it illegal.
Dealer:
All right.
—Found in Harper’s Magazine, March 2001