Cratylus
Cratylus

Reputation: 54074

How to return the correct type of list?

If I have a method like this (for simplicity assume integers):

public static List<Integer> doSomething(List<Integer> list) {
   // logic here  
}

and I need for my processing to create internally a new list which I will create and somehow populate and return to the caller, how can I do it since I don't know what type of list the caller passed in?

I don't want to return a List of different type that what the caller passed in.

E.g. If the caller passed a LinkedList and I don't want to return an ArrayList.

How can this issue best be approached?

Upvotes: 4

Views: 3287

Answers (5)

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147154

The best thing to do is to remove the list creation from the method. Have the caller decide how to create the list:

public static void doSomething(List<Integer> dest, List<Integer> src) {

Upvotes: 1

david van brink
david van brink

Reputation: 3642

If you really, really care what kind of object comes out, I would include that as a parameter to the method, like:

<T extends List<Integer>> T doSomething(Class<T> returnType,List<Integer> v)
    throws Exception
{
    // constructors for your return will be tricky :)
    // returnType.newInstance() will probably work.
    T result = returnType.newInstance();
    result.add(86); result.add(99);
    return result;
}

Upvotes: 0

esaj
esaj

Reputation: 16035

You could use Class.newInstance to create a list of the passed in type:

public static List<Integer> doSomething(List<Integer> list)
{
    List<Integer> newList = null;
    try
    {
        newList = list.getClass().newInstance();
    }
    catch(InstantiationException e)
    {
        throw new RuntimeException(e);
    }
    catch(IllegalAccessException e)
    {       
        throw new RuntimeException(e);
    }

    //Logic here

    return newList;
}

@Test
public void test()
{       
    List<Integer> testList = new ArrayList<Integer>();

    List<Integer> resultList = doSomething(testList);
    Assert.assertEquals(testList.getClass(), resultList.getClass());
    Assert.assertNotSame(LinkedList.class, resultList.getClass());

    testList = new LinkedList<Integer>();

    resultList = doSomething(testList);
    Assert.assertEquals(testList.getClass(), resultList.getClass());
    Assert.assertNotSame(ArrayList.class, resultList.getClass());       
}

Upvotes: 0

&#211;scar L&#243;pez
&#211;scar L&#243;pez

Reputation: 236004

You shouldn't tie your implementation to a particular implementation of List, the idea of using an interface is that, from the outside, it shouldn't matter what concrete class you're instantiating as long as it conforms to the List interface.

EDIT :

Anyway, here's a possible way:

List<Integer> lst1 = new ArrayList<Integer>();
Class<?> klass1 = lst1.getClass();
List<Integer> copy1 = (List<Integer>) klass1.newInstance();
System.out.println(copy1.getClass().getName());
> java.util.ArrayList

List<Integer> lst2 = new LinkedList<Integer>();
Class<?> klass2 = lst2.getClass();
List<Integer> copy2 = (List<Integer>) klass2.newInstance();
System.out.println(copy2.getClass().getName());
> java.util.LinkedList

As you can see in the console, the copies are instances of the same class as the original list.

Upvotes: 7

Mike Samuel
Mike Samuel

Reputation: 120506

If you can get away with just using one of those two output types, then you can do

if (inputList instanceof RandomAccess) {
  // use an ArrayList
} else {
  // use a LinkedList.
}

The RandomAccess interface is meant to indicate that the implementation allows O(1) get operations.

Marker interface used by List implementations to indicate that they support fast (generally constant time) random access. The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.

By doing this, your APIs allow clients to defend their inputs. They can pass in the result of Collections.unmodifiableList(...) and be sure that it isn't modified by other code.

If you really know the input is a mutable list, you can clone() the list, then clear() it. Both ArrayList and LinkedList have public clone() methods which can be accessed reflectively.

Upvotes: 4

Related Questions