views:

114

answers:

6

Let's say I had:

protected void performLogic(List<Object> docs) {
  ...
}

In the code where I'm going to be calling this method, I have a List<String> list. I want to call performLogic, passing this list. But it won't work because the lists are 2 different types:

public void execute() {
    List<String> docs = new ArrayList<String>();
    performLogin(docs);  // won't work
}

I tried casting to List<Object> also, but that won't work either.

So is the only way to do this is to make a new ArrayList of Object and just add the values and then pass it? Just seems cumbersome. I wondered if there was a better way to do it.

Thanks.

+2  A: 

Its silly but you have to say T extends Object

protected static <T extends Object> void performLogic(List<T> docs)

Oh and its if part of a public API you can do this trick:

performLogic((List) var);

Just be careful as it will fail during runtime if var isn't an List of Objects. But lucky for you it is.

Pyrolistical
I can't change signature of performLogic, it's part of a provided API.
dcp
Since all java classes are derived from Object, it's IMO not possible for the cast to fail at runtime.
Michael Borgwardt
@Michael - +1, the real risk is that "performLogic" could try to add a non-String. If he knows that can't happen, that risk is mitigated.
jsight
@Michael my point is that in other cases you can create runtime failures if you are not careful. IE. It is generally dangerous to do this
Pyrolistical
+1  A: 

This would work as well (though bypassing typesafety):

performLogic((List)docs);
jsight
-1 Completely ignoring the real issue! I would unaccept this answer.
Kevin Bourrillion
I got downvoted for pointing out the issue O_o
Vivin Paliath
@Kevin - If by "the real issue" you mean that the API is badly designed, I think that has already been covered. If he has to use the badly designed API, this is one possible way to do it. Its ugly, but sometimes using other people's APIs is necessarily ugly.
jsight
@Kevin in the real world sometimes you have to use badly designed APIs. The question asker clearly stated that this is a 3rd party API that he doesn't not have the ability to change.
mbaird
I'm very sorry, then. The question should have been edited -- one shouldn't have to read all the comments just to understand what's being asked. Still, I'd like to remove my downvote, but it appears I'm not allowed.
Kevin Bourrillion
(Actually, as far as I know, that comment may not have even been there when I downvoted, so I partially de-apologize. :-))
Kevin Bourrillion
+3  A: 

I think having List<Object> is a bad pattern since it really isn't that much better than List without generics. Generics are useful when you want to enforce type-safety in complex objects. As such they are really useful for enforcing type-safety in data structures.

You need to look at your algorithm and decide if you really want to accept a list of Object. That aside, can also forcibly cast it, but then you would be completely disregarding type safety.

Vivin Paliath
I'm voting this up just b/c it is the theoretically right solution. Keep in mind that its not possible given the preconditions of the question, tough.
jsight
@jsight, I didn't notice that he said this was a 3rd-party API (he noted it in the comments but not in the question). Thanks for pointing that out to me, though.
Vivin Paliath
I don't think List<Object> is exactly a "bad pattern"; it's just very rarely what you want. It means "a List I can put any kind of object into." It is much different from raw "List", which essentially should _never_ be used.
Kevin Bourrillion
I see what you're saying. But I also think it's very rare that you'd want to have a list into which you can insert any object. Not saying that there aren't those cases, but you probably have to think really hard if that's what you really want.
Vivin Paliath
A: 

The correct solution would be to try and have that broken API fixed. Using List<Object> as parameter is simply a misuse of Generics.

Until the API improves, you can cast to the raw type:

performLogin((List)docs);

It will still result in a compiler warning, though.

Michael Borgwardt
Correcting the broken API that the OP does not have access to is not an option, so there is no reason to comment about it.
pcm2a
@pcm2a: "it's not my code" doesn't mean you can't at least contact the people whose code it is and point out the flaw - especially since the fix is downwards-compatible. Sometimes people do listen, you know?
Michael Borgwardt
+1 I appreciate Michael's emphasis on this avenue of solution. Also, the third-party nature of the API is not even mentioned in the question, only in a comment.
Kevin Bourrillion
+1  A: 

If the list doesn't need to be modified within performLogic you can use Collections.unmodifiableList to safely cast the list. Ex:

performLogic(Collections.unmodifiableList(docs));

To understand why this works you have to first understand why you can't just pass in docs as-is. The reason for that is a List can have any instance of object added to it (for instance an Integer). If the List reference were used later there would be an error because the Integer added to the list couldn't be cast to String. Making the list unmodifiable prevents this possibility so it is then safe to pass an unmodifiable List as a List.

Geoff Reedy
+2  A: 

If you do not add elements to the docs, you can change API to

protected void performLogic(List<?> docs);

All previous code that uses performLogic will continue to compile.

Ha