Tuesday, January 2, 2007

Code Tip: Statically Check Multiple Interfaces

WARNING: This blog entry was imported from my old blog on blogs.sun.com (which used different blogging software), so formatting and links may not be correct.


You may think generics is all about avoiding casts in collections. However, I found a really good use for them the other day that's pretty useful.



Let's say you have a method which takes a List and does something with it.


void doSomething(List list) {
...
}

(In my code, it's actually List<String>, but I'm trying to keep other generics out of this to motivate those of you still needing a good reason to learn them.)



In my case, I needed to iterate over the list in reverse order. Uh oh, that's going to be pretty expensive for some types of lists, and if I switch my implementation to for example a LinkedList in the future, I'd like to revisit this. Obviously, I could make my method the following:


void doSomething(ArrayList list) {
...
}



However, using specific implementation classes rather than interfaces is frowned upon, and besides, this needlessly prevents the method from being used with other random access list. On the other hand, I would like to state in some way that this method really wants to be able to access the list elements in random order.



java.util.RandomAccess to the rescue. Lists that provide random access implement this interface. But what do I put in my method signature? RandomAccess is not itself a List. I really want to specify multiple constraints on my parameter.



This is precisely what generic methods allow! The following method declaration will accomplish what I want:


<T extends List & RandomAccess> void doSomething(T list) {
...
}



Here we're saying that my parameter T is a generic type, which satisfies multiple constraints: it both extends List and it implements RandomAccess! You can pass an ArrayList to the above method, but not a LinkedList!



Think hard about the constraints you add. In some cases, adding a RandomAccess constraint on a method is leaking implementation through to the client - it reveals something about the implementation behind the method signature that may change later. I find this most appropriate within implementation code.


2 comments:

  1. Nice example. Thanks for sharing it.

    ReplyDelete
  2. Very helpful. Excellent reason to learn generics beyond the simple use cases in type-safe collections.
    Joshua Smith

    ReplyDelete