dacDave
dacDave

Reputation: 242

How to return an interface from a method

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

Answers (3)

Unihedron
Unihedron

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

ucsunil
ucsunil

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

Rahul
Rahul

Reputation: 3509

Your method signature should be as below

Public Collection(? super List) findAvailableLanguages(){}

Upvotes: -1

Related Questions