56

I want to convert List<String> to List<Object>.

One of the existing methods is returning List<String> and I want to convert it to List<Object>. Is there a direct way in Java other then iterating over and converting element by element?

ZoogieZork
  • 11,215
  • 5
  • 45
  • 42
Alexs
  • 625
  • 2
  • 6
  • 5
  • 4
    `String` is `Object` why do you need it? – khachik Nov 26 '10 at 19:34
  • 7
    You might need to pass the list to a function that expects a `List` – Riley Lark Nov 26 '10 at 19:40
  • 15
    What exactly are you trying to do? Because of type erasure, a List is a List. If there's a method you have that take a List, that method should be modified to List extends Object>. If you're not in control of that method, then follow any of the answers below. – Reverend Gonzo Nov 26 '10 at 19:46
  • Yes, I have requirement to convert to List as i have to pass it back to another method which accepts like List. – Alexs Nov 26 '10 at 20:01

7 Answers7

102

Pass the List<String> as a parameter to the constructor of a new ArrayList<Object>.

List<Object> objectList = new ArrayList<Object>(stringList);

Any Collection can be passed as an argument to the constructor as long as its type extends the type of the ArrayList, as String extends Object. The constructor takes a Collection, but List is a subinterface of Collection, so you can just use the List<String>.

Erick Robertson
  • 32,125
  • 13
  • 69
  • 98
  • 4
    This constructs unnecessary objects and can, if this is a big list, potentially take up a lot of memory. Just cast it. – Martin Algesten Nov 26 '10 at 19:44
  • 2
    Read my comment on your answer. Casting it is the wrong solution. This answer doesn't deserve a downvote. – Erick Robertson Nov 26 '10 at 19:45
  • Sure. I'll remove the downvote (6 mins or edit it says). But mine doesn't deserve one either. – Martin Algesten Nov 26 '10 at 19:50
  • @Martin. It created just one extra object ( with its internal machinery which is small ) Even if the list is huge, there is no a significant impact in the memory usage, because what is being stored are reference values. There is not a deep copy involved. Plus, this would keep using the generics to force the collection of the same type, while casting would just throw it away – OscarRyz Nov 26 '10 at 19:59
  • 3
    I just today cracked a memory-hog with a list growing to 90+ million elements, just references, allocating a total of 1.3GB in one thread (and I had 4-5 of those threads). A bug, admittedly, but in normal cases the list would be max 5.7 million, still significant. It comes down to situation and the pragmatic choice. Casting is not a blank no no. – Martin Algesten Nov 26 '10 at 20:07
29

Any java collection is just a collection of objects be it string or other. The type argument is just sugar. Depending on situation, such as dealing with very large lists, you may just want to convert it - obviously risking mixing two different types of objects in the same list.

List<Object> objectList = (List)stringList;

And put a @SuppressWarning to get rid of nasties...

Martin Algesten
  • 13,052
  • 4
  • 54
  • 77
  • 4
    It really isn't. Why would you construct new collections when you already got what you need? It's rational and efficient. – Martin Algesten Nov 26 '10 at 19:43
  • 9
    You will then have two references to the same object. One reference thinks it's a `List` and the other thinks it's a `List`. If you add objects using the new reference which are not strings, the old reference will not be able to access them without throwing a `ClassCastException`. – Erick Robertson Nov 26 '10 at 19:44
  • 3
    Yes, you can obviously slip up, mixing apples and pears, but depending on situation, this may be exactly what's required. If this for instance was a list local to a method and not exposed, I wouldn't hesitate to do this. It's a pragmatic choice. – Martin Algesten Nov 26 '10 at 19:52
  • 2
    Ok, I've clarified that you need to know what you're doing. – Martin Algesten Nov 26 '10 at 19:57
  • I agree that in _some_ situations where you want to be more efficient and use less memory this is the way to go. That said, I'd always inline such a cast so that no local variable would exist with the misleading type. E.g. `callUglyLegacyCode((List) strings)`. – qben Apr 02 '16 at 21:09
6

Personally, while both of the currently top rated answers are right in a way, I do not think any of them solves the problem in an elegant, reusable way, especially if you have to do this very often.

Suppose you have some old legacy code / dependency that you cannot change in any way (so that it would at least accept List<? extends Object> as @ReverendGonzo suggested in his comment. Suppose also, that you need to talk to this legacy module a lot.

I do not think either casting / copying all the time would be bearable on the long run. It makes your code either vulnerable to insidious bugs and hard to follow or slightly (or drastically) inefficient and hard-to-read.

To have readable and efficient production code, it is better to encapsulate the dirty part in a separate module which deals with the otherwise harmless but ugly cast.

class ProductionCode {
    public void doJob() {
        List<String> strings = Arrays.asList("pear", "apple", "peach");
        StringMagicUtils.dealWithStrings(strings);
    }
}

class StringMagicUtils {
    @SuppressWarnings("unchecked")
    public static void dealWithStrings(List<String> strings) {
        ExternalStringMagic.dealWithStringsAsObjects((List) strings);
    }
}

// Legacy - cannot edit this wonderful code below ˇˇ
class ExternalStringMagic {
    public static void dealWithStringsAsObjects(List<Object> stringsAsObjects) {
        // deal with them as they please
    }
}
Community
  • 1
  • 1
qben
  • 813
  • 10
  • 22
5

If you are willing to convert to an unmodifiable List<Object>, you can simply wrap your list with Collections.unmodifiableList. This works because this static method has a proper wildcard type ? extends T for the element type of the wrapped list (where T is the type of the result list).

Note that, in most cases, creating an unmodifiable view is what you should do, otherwise objects of different types (other than String) may be added in the original list (which should only hold Strings).

Michail Alexakis
  • 1,405
  • 15
  • 14
4

This is pretty inefficient, but at least you don't have to write a lot of code~

List<String> stringList = new ArrayList<String>();
List<Object> objectList = Arrays.asList(stringList.toArray());
Riley Lark
  • 20,660
  • 15
  • 80
  • 128
  • Tks. I think this won't create a new ArrayList in memory just convert original stringList to List. – Alexs Nov 26 '10 at 19:56
  • @Alex It doesn't create a new ArrayList, but it creates an internal unmodifiable private List implementation, which happen to be pretty much like ArrayList. The effect is very similar, but you'll have problems if you need to add a new element to that list. Plus, the memory you "think" you're saving is being used in creating the new array after: `stringList.toArray()` a new allocated array is created after that. – OscarRyz Nov 26 '10 at 20:03
1
List<Object> ofObjects = new ArrayList<Object>(ofStrings);

as in:

import java.util.*;
class C { 
  public static void main( String[] args ) { 
     List<String> s = new ArrayList<String>();
     s.add("S");
     List<Object> o = new ArrayList<Object>(s);
     o.add( new Object() );
     System.out.println(  o );

  }
}

As an alternative you can try the addAll method, if the list of objects is an existing list.

OscarRyz
  • 196,001
  • 113
  • 385
  • 569
0

model.class

public class Model {

private List<String> stringList = new ArrayList<>();

public List<String> getStringList() {
    return stringList;
}

public void setStringList(List<String> stringList) {
    this.stringList = stringList;
}

}

MainActivity

public class MainActivity extends AppCompatActivity {

Model model = new Model();
Spinner spinner;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    spinner=findViewById(R.id.spinner);

    List<String> itemList = new ArrayList<String>();
    itemList.add("item1");
    itemList.add("item2");
    itemList.add("item3");


   model.setStringList(itemList);


    ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, model.getStringList());
    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

    spinner.setAdapter(dataAdapter);

}

}

Mosayeb Masoumi
  • 481
  • 4
  • 10