Why Java is Not My Favorite Language — Reason #16.

UnsupportedOperationException. Why, in the name of all that is good and right, would you have such a dumb exception? Either the operation is important or it is not. If it is not don’t clutter the interface with it. If it is it ought to actually be implemented.

I have known about UnsupportedOperationException for a while now but I had not run into a method that actually threw it until yesterday. That method was ArrayList.remove(). I can just hear the lame argument for having this method throw UnsupportedOperationException now, “Removing an item from the underlying array would inefficient and/or hard to write.” If you feel any of that matters fine, but don’t lie to me and tell you have a bunch of operations, by claiming you implement the List interface, and then blow up in my face when I try to use one of those operation.

If remove() is really not a fundamental operation for lists (which I would debate, but whatever) it should not be part of List. There should be a RemoveList, or some such, interface which implements List and adds remove(). Interfaces are free, you can have as many of them as you need.

If you do not actually implement all methods of an interface you have no right to claim you implement the interface, regardless of what the javadoc comments say.

{Update: Curt Cox pointed out that I was, in fact, not using the normal ArrayList class. The offending class was actual java.util.Arrays$ArrayList which I can only assume, since there are no Javadocs for it, is an intentionally broken version of ArrayList.}

12 comments on “Why Java is Not My Favorite Language — Reason #16.

  1. - Post author

    Those are interesting but that do not change my mind. I do not dispute that it would have been more difficult to implement but I do not consider “doing it well is hard” to be an acceptable defense for crappy APIs for some of the most basic parts of the language.

    You make a good point about which collection I was actually using. It was whatever class is returned by Arrays.toList(), which I assume is an ArrayList but I did not check so I might well be wrong.

  2. -

    I couldn’t agree more with Peter’s points (ex. “If you do not actually implement all methods of an interface you have no right to claim you implement the interface”).

    So far as I know, the UnsupportedOperationException is really there to allow a statically typed language like Java to emulate/simulate/pretend-to-be a dynamically typed language.

    IMO, the use of casting after retrieving objects from a pre-generics or heterogenous collection is basically in the same category of “baddness”.

    Cheers,

    Geoff S.

  3. -

    Arrays.asList() does NOT return a java.util.ArrayList. It return a java.util.Arrays.ArrayList. The remove method on java.util.ArrayList is properly implemented.

  4. -

    hmm, yeah, you’re using the API incorrectly. no wonder it’s not your favorite, you haven’t taken the time to write the code correctly. you’re probably using an unmodifiable list which came from a convenience call. now, why doesn’t the java api just accomodate lazy programmers and make the code slower, so then you can complain how slow it is…

  5. -

    I disagree with the most general, intermediate and most specific claims. However I agree that Java is not your favourite language. It’s not mine either. I would rather go with a latently typed language in which interfaces mostly don’t exist and unsupported operation is normal.

    For the intemediate claim, given a large taxonomy of classes which support various sets of a group of methods creating a *useful* hierarchy of interfaces is, in general, an unsolvable problem. You either end up an specific interface for the particular implementation, or a set of 5 declarations of different sub interfaces. It is a waste of time to head in this direction.

    For the most specific claim, Arrays.toList returns a live “List’ish” view of an array (via an inner class java.util.Arrays$ArrayList. If you modify the elements of the List view the underlying array changes and vice versa. So elements can not be truely removed from the list view because the other view (the underlying array) can not be scaled.

    For the most general claim, if something is hard, it is frequently not worth doing. In this case the purpose of the interfaces is to communicate quickly and clearly. The additional complication in communicating via a complex taxonmy of interface is not worth it, because communicating in other ways, is more effective and efficient. More Interfaces are not free for humans and thinking about whether I want RemoveList or List is mostly not worth it.

    Brendan

  6. - Post author

    Brendan,

    I get that Arrays.asList() is intended to return a List-ish thing to represent the array. Given that, thing to do is to return a List-ish thing, not a List. I understand that all the list methods might not be appropriate in all cases. In those cases I would argue you are not implemeting the interface and therefore should not claim that you are.

    The problem I have with this is that to use an interface with optional operations I have to have a completely inappropriate understanding of the implementation details of all the classes involved. In this case, I need to know that Arrays.asList() returns something that does not have a remove method (which I can only tell by looking that the code, or by trial and error) and I need know if the method I am passing the List to uses remove() (which I can only tell by looking that the code, or by trial and error).

    I agree that large hierachries can be problematic but I think that optional operations fly in the face of the very concept of an interface.

  7. -

    This sounds like a job for… (superhero music in the background) the const keyword!

    Seriously, if the interfact would’ve declared get() method as a const method and remove() as non-const. Then the method toList() would’ve returned a const version of the List. You not allowed to call non-const functions on const object, so the compiler would’ve caught the “mistake”.

    Ah! The beauty of C++! :)

  8. -

    Yuriy –

    Except the result of Arrays.asList is not const. You can change the element values. You just can’t change the size of an Array.

    I remember const in C++ and think it was a useless pain. Most of my variables are acutally const, although rarely initially declared that way. When I called something that required const the effect would ripple back through my code adding const to things (or I could just cast it away). All that finger typing never helped me find one bug.

    Peter –

    I agree, the reason you have UnsupportedOperationException is so that you can fly in the face of the very meaning of an Interface. That is what the designers of the collections wanted to do. They wanted runtime typing for their design. They needed to work in the strongly typed Java environment and make the compiler happy.

    You are saying they should have produced a more statically typed design. I suggest the evidence about reliability and productivity suggests that we should drop strong typing altogther.

    Brendan

  9. -

    Thanks for the extra info..

  10. -

    Java is my favorite language for now, but I hate the UnsupportedOperationException. Why have an interface if they don’t have to support all of the features? Another thing I hate about Java is related. It seems like a good portion of the time, I don’t really care if my code throws an exception. (closing files or sockets) They should add an ignore keyword to ignore exceptions to make my code cleaner. :sorry about the 2 o’clock rant:
    Back for the subject of the UnsupportedOperationException. I think this is something the compiler should be warning me about, not something I have to look up in the API. I see “implements List”, I believe it implements List.

  11. -

    java cannot defeat c because java is just a copy paste language

Comments are closed.