Reputation: 242
Here is my method. I want to return a collection of strings from a Java method. I would like for the calling code to decide whether it wants to implement this collection as a Vector
or a LinkedList
or an ArrayList
or something else that implements the List
interface.
public List<String> findAvailableLanguages() {
Iterator<Map.Entry<String, String>> it = this.iterator();
List<String> list = new ArrayList<String>();
while (it.hasNext()) {
Map.Entry<String, String> n = it.next();
list.add(n.getKey());
}
...
However, I must instantiate a concrete class object inside of the method in order to build the collection. What do I now return that will be compatible with any class that implements List
?
Is this possible?
Upvotes: 1
Views: 145
Reputation: 11041
It's more effective for the callers if you allow a List
to be passed in the filling process instead of initiating your own. It will also make for code that's easily unit-testable, as this does the pattern known as Dependency Injection.
public List<String> populateWithAvailableLanguages(List<String> list) {
Iterator<Map.Entry<String, String>> it = this.iterator();
// List<String> list = new ArrayList<String>();
while (it.hasNext()) {
Map.Entry<String, String> n = it.next();
list.add(n.getKey());
}
}
Now the implementation of the List
can be specified by the caller:
List<String> availableLanguages = new ArrayList<>();
Localizer.populateWithAvailableLanguages(availableLanguages);
Upvotes: 4
Reputation: 7494
In short, returning an ArrayList object type that can be cast into any other object type that implements List is not possible. The elements can be traversed and added to another object type but the collection type itself cannot be cast.
I'll explain why. When you say,
List<String> list = new ArrayList<String>();
the reference type of 'list' is List and the object type is ArrayList. The 'list' object that you now have gives you access to all the methods of the List interface but not to the other methods that ArrayList has although the list object can see them (kind of like a narrowing conversion). You can cast this list object back to an ArrayList object and that would work because the list instance anyway could see the methods that ArrayList had and hence casting this back will work (kind of like a widening conversion back to the original width).
But if you were to cast it to one of the other classes implementing the List interface like LinkedList or Vector or Stack, what will happen? The list instance does not know how the other methods present in LinkedList, Vector or Stack are implemented (as they are not in ArrayList). So it's kind of like a conversion where you do not know what needs to be done. So it will throw back a compiler error.
Extending this, you can see, if you had:
List<String> list = new LinkedList<String>();
now, casting the list back to a LinkedList will work but not back to an ArrayList.
Upvotes: 1
Reputation: 3509
Your method signature should be as below
Public Collection(? super List) findAvailableLanguages(){}
Upvotes: -1