Java - Mixed ArrayLists?
Asked Answered
N

3

11

Is it possible to store a mixture of object types in an ArrayList? If so how?

This is what I have tried so far:

List<Object> list = new ArrayList<Object>();

list.add(new String("Hello World"));
list.add(new Integer(1));
list.add(new Long(1l));

for (i = 0; i < list.size(); i++) {
    if (list.get(i) instanceof String){
        sqlPreparedStatement.setString((i+1), (String) list.get(i));
    } else if (list.get(i) instanceof Integer) {
        sqlPreparedStatement.setInt((i+1), (Integer) list.get(i));
    } else if (list.get(i) instanceof Long) {
        sqlPreparedStatement.setLong((i+1), (Long) list.get(i));
    }
}

But it throws a casting exception.

Thanks in advance for any input!

Neille answered 10/6, 2011 at 0:11 Comment(5)
Define "doesn't work".Grath
Why parametrize with Object? What do you get with that?Haul
@Jeremy: It avoids irritating wiggly yellow underlining in Eclipse!Grath
Show the stack trace of your exception, please. The interesting point would be the line number of the ClassCastException (and mark this number in the source). The source looks fine, apart from some optimizations like in the answer from scientiaesthete, and the superfluous new String(...) there.Anarch
@Paulo is correct. The right way to figure out what is going wrong is to look at a stack trace. Does the order of your List match what's happening in your PreparedStatement?Melainemelamed
S
20

This is what you should have:

List<Object> list = new ArrayList<Object>();

list.add(new String("Hello World"));
list.add(new Integer(1));
list.add(new Long(1l));

for (Object obj: list) {
    if (obj instanceof String){
        sqlPreparedStatement.setString((String) obj);
    } else if (obj instanceof Integer) {
        sqlPreparedStatement.setInt((Integer) obj);
    } else if (obj instanceof Long) {
        sqlPreparedStatement.setLong((Long) obj);
    }
}
Saks answered 10/6, 2011 at 0:15 Comment(8)
There's no need for the "new String()" by the way.Ditty
@Saks : Apart from List#get(int) getting called twice as many times as in yours, and the use of an iterator, there is no difference between your code snippet and the OP's. Am I missing something here - what is the difference with regard to casting?Cordova
@Cordova The setXXX() signatures are different. The OP's had setXXX(int, XXXthing), this one has just setXXX(XXXthing). One of them doesn't match the API, methinks.Melainemelamed
@Atreys: yep, this "answer" is in the wrong, and in fact the OP's code is the better of the two since it in fact compiles and gives the for loop an int parameter that can be used in the prepared statement's method calls. I have to wonder how this answer got 5 up-votes? Down-voted by me.Charlottcharlotta
Actually there's no need for any of the news with autoboxing.Intercessor
@Paul Cager That was actually just to demonstrate the different object types. As this is just demo code I wanted to clearly demonstrate the different objects types being used.Neille
@Melainemelamed @Saks @Hovercraft : I still can't see how this would make a difference w.r.t. casting...Cordova
@bguiz. You're right. it doesn't make a difference w.r.t. casting in the visible codeMelainemelamed
C
13

Sorry to crash your parade, but you shouldn't be using an ArrayList of 3 (or any) different types to begin with. If the information is related, create a class that holds the related information and create an ArrayList that holds only one type: objects of this class.

Edit 1:
For instance say a class to hold the data like so:

class SqlData {
   private String textData;
   private int intData;
   private long longData;

   public SqlData(String textData, int intData, long longData) {
      this.textData = textData;
      this.intData = intData;
      this.longData = longData;
   }

   public String getTextData() {
      return textData;
   }

   public int getIntData() {
      return intData;
   }

   public long getLongData() {
      return longData;
   }

}

and used like so:

  List<SqlData> sqlDataList = new ArrayList<SqlData>();
  sqlDataList.add(new SqlData("Hello World", 1, 11L));

  for (int i = 0; i < sqlDataList.size(); i++) {
     try {
        sqlPreparedStatement.setString(i + 1, sqlDataList.get(i).getTextData());
        sqlPreparedStatement.setInt(i + 1, sqlDataList.get(i).getIntData());
        sqlPreparedStatement.setLong(i + 1, sqlDataList.get(i).getLongData());
     } catch (SQLException e) {
        e.printStackTrace();
     }
  }
Charlottcharlotta answered 10/6, 2011 at 0:55 Comment(5)
This approach is more descriptive. But I think we don't need a sqlDataList and a for loop here.Playboy
+1 @Hovercraft : Just to counteract the "revenge" downvote you likely got; AND I also agree that you shouldn't be mixing objects of different types within any List in the first place; WITH the possible exception of types which are inherited (obeys the "is-a" rule)Cordova
Even though you shouldn't mix objects of different types in a List, that doesn't mean people can't and that there isn't software out there that has this type of code in it.Melainemelamed
@Atreys: It's not a matter of "can't", but more of a matter of creating software that is difficult to debug, maintain and extend when one follows bad practices such as this.Charlottcharlotta
I really like this answer because it teaches you the right way to do things! So often, people give answers just to give answers, rather than looking at the big picture!Colman
R
5

Why are you making this so hard? PreparedStatement has a setObject() method - just use that:

    List<Object> list = new ArrayList<Object>();
    list.add(new String("Hello World"));
    list.add(new Integer(1));
    list.add(new Long(1l));
    for (int i = 0; i < list.size(); i++)
        sqlPreparedStatement.setObject(i + 1, list.get(i)); // NOTE: columns count from 1

NOTE: The java SQL API counts everything from 1, not from zero, so columns are numbered 1...size() and not 0...size()-1

Raimund answered 10/6, 2011 at 1:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.