2

I am receiving a large number of arraylists of objects that extend my object. I want to insert them into a hashmap for faster referencing. I decided to create a method to avoid duplicate code since it happens so often, and just for fun I want to be extra fancy and use generics. There are a few ways I know to do this, but none seem very clean or pretty; I'm wondering if I'm missing an easier solution. So I want to do something like this...

private void addToMap(Collections<? extends myObject> collection, Map<String, ? extends myObject> map){

  for(MyObject myObject: collection){
    map.put(myObject.getName(), myObject);
  }
}

The contract of the method would require that the collection provided stores the same class as map does. I'm fine if the method throws an exception were someone to break that contract and try passing in two a collection that stored a different implementation of myObject then the map stored.

The code above fails, because I can't put 'myObject' into a collection expecting "? extends MyObject" to encourage type safety. I'm fine just casting it, but they only way I know to figure out how to cast it involves a few steps of ugly reflection and seems convoluted. I could also create some sort of inner class to have more powerful generics available to me (to force collection and map to store the same type) but it also feels like overkill.

So, is there a simple or pretty manner to creating this method in the most intuitive-to-the-reader manner possible? I know I could toss out the generics entirely and just cast everything from object, I'm just trying to figure out a more elegant method.

dsollen
  • 6,046
  • 6
  • 43
  • 84

2 Answers2

3

It sounds like you want the following:

private <T extends MyObject> void addToMap(
        Collection<T> collection,
        Map<String, ? super T> map
) {
    for (T myObject : collection) {
        map.put(myObject.getName(), myObject);
    }
}

More info:

Community
  • 1
  • 1
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
  • If you wanted to make this solution even more flexible you could use `Collection extends T>`. – Jeffrey Mar 21 '13 at 01:09
  • @Jeffrey I considered that but it wouldn't add any further flexibility for the caller, since it already decides `T`. Thanks for the edit btw. – Paul Bellora Mar 21 '13 at 01:10
  • @Jeffrey Any reason you deleted your answer? I was about to abandon mine and upvote it. – Paul Bellora Mar 21 '13 at 01:12
  • 1
    I was going to edit in an explanation about the difference between `? extends` and `? super`, but your links have it covered (I'm saving that PECS one for later :)). +1 – Jeffrey Mar 21 '13 at 01:17
  • ah, I didn't think it would let me get away with generics like that in a method (rather then class level). I tried it already; but guess I got the syntax wrong somehow – dsollen Mar 21 '13 at 14:28
  • @dsollen I actually just fixed a typo in my answer - see my edit. – Paul Bellora Mar 21 '13 at 14:30
  • I was missing though just so you know void should come after the , in case youw ant to update it for anyone else who needs help. Thanks again! – dsollen Mar 21 '13 at 15:06
0

I think that depends on.

Generics is designed and suitable in some senarios, in which the client code and service code are contracted tightly for stong-type transfering and evaluating. so Generics just offers us Precompile-time Safety in this cases, BUT it is not absolutely safe and convenient when client code do a silly casting to a wrong type and input them to Genrics collection. As we know the colleciton will collapse in runtime , but it is ok in compile-time.

Generics is NOT suitable in some cases, in which we ourselves can guarantee some objects which we add to generics collection are correct, even they cannot be unifed or casted to one superclass strong-type. in this case, we can ignore generics by using raw type collections or using some collection like List<Object>. it 's right way to go. I think you maybe be in this cases.

Henry Leu
  • 2,184
  • 4
  • 22
  • 34