You are viewing mackys

Adventures in Engineering - Java Generics and Downcasting - FAIL.
The wanderings of a modern ronin.

Ben Cantrick
  Date: 2008-03-12 15:34
  Subject:   Java Generics and Downcasting - FAIL.
Public
  Music:Deathklok - Hatredy

Suppose you have an ArrayList of MimeMessages:

ArrayList<MimeMessage> messages = new ArrayList<MimeMessage>(20);

You add some messages to it...

messages.add(thisMsg);
messages.add(thatMsg);


...and then the method you're coding up has to return a list of messages. This has to be a MimeMessage[] array, and you can't change that due to hysterical porpoises. So how do you do this?

Well, hey, this should be easy, right? ArrayList has a toArray() method. So just...

return messages.toArray();

...and Bob's your uncle. Right?

RIGHT?

HAHAHAHAHAHAHA, YOU STUPID, DELUDED FOOL! toArray() returns an array of Object, not an array of what you created the ArrayList as! I mean, what were you thinking - expecting a collection of type Foo to convert into an array of Foos? That's just crazy talk!

No, Java doesn't care that your ArrayList was template instantiated on MimeMessage, thus ensuring beyond any possible doubt - at compile time - that every item in message Is-A MimeMessage! And no, Java doesn't care that it has Run-Time Type Identification and thus also knows damn well at run-time exactly what type of objects are in your ArrayList! But no, in spite of all that, .toArray() still will not return a list of MimeMessages!

Now... just GUESS which of the following syntaxes you must use to make this stupid little bullshit operation actually work the way it should:


1) (MimeMessage[])messages.toArray();

BZZZZZZZT! javac whines about "incompatable types". See earlier re: No, we don't care that Java damn well knows (at compile time!) that those are all MimeMessages in messages.


2) messages.toArray(MimeMessage[]);

BZZZZZZZT! javac: "Expected ".class" at []"


3) messages.toArray(MimeMessage[].class);

BZZZZZZZT! javac: "cannot find symbol: method toArray(java.lang.Class<javax.mail.internet.MimeMessage[]>)"


Do you give up yet?

messages.toArray(new MimeMessage[1]);


Yes, that's right: You have to manually allocate an array of the proper type yourself, and then pass it off to the toArray() call!

Bonus lulz: If the array you pass off is too small, toArray() will trash it and create a new one for you, one that is big enough to hold the contents of the ArrayList! In other words, not only is .toArray() perfectly capable of doing the heavy lifting for you, it will in fact do exactly that... just as long as you first jump through a stupid, pointless hoop that's completely and utterly unnecessary!!


But the very worst thing? This problem is years and years old. I just ran into this myself for the first time today, but this has been happening ever since generics went into Java - which is going on four years now. You have to ask yourself, "Why the hell would they even bother to do generics, but then do it so insanely badly?" The only answer I can think of is: because they're stupid as hell, and frankly they don't care to get this right.


"Simple things should be simple, complex things should be possible." -Alan Kay

The way Java chose to implement generics makes simple things counter-intuitive and complex things unmaintainable. And guess what that means for you, Sun?



Now getcher ass on-board!

Oh wait, you already did...
Post A Comment | 8 Comments | Add to Memories | Share | Link



Ben Cantrick
  User: mackys
  Date: 2010-02-28 10:04 (UTC)
  Subject:   Re: Thanks Ben
Most welcome.
Reply | Parent | Thread | Link



browse
July 2014