2

Let's suppose I'm using a library for which I don't know the source code. It has a method that returns a List, like so:

public List<SomeObj> getObjs() { ... }

I'm wondering if this is a good idea:

ArrayList<SomeObj> objs = (ArrayList<SomeObj>) getObjs();

If, for example, the concrete implementation of the List inside getObjs() is a LinkedList then wouldn't there be some kind of type discrepancy?

soren.qvist
  • 7,376
  • 14
  • 62
  • 91

9 Answers9

6

No, it is not a good idea. You should always use the interface (List) to declare your list variable unless you for some reason need specific behaviour from ArrayList.
Also, if you do, you need to be really sure that the list returned is an ArrayList. In this case, the promised contract of getObjs() is only that the return type is some kind of List, so you shouldn't assume anything else. Even if the List returned now would be ArrayList , there is nothing preventing the implementer of getObjs() to later change the type of List returned, which would then break your code.

Keppil
  • 45,603
  • 8
  • 97
  • 119
  • 1
    Or to add to the point, the method may even return different list implementations depending on input or result size (For example we have methods in our project that do return a special 'read-only-empty' list in some methods if the list would be empty). – Durandal Aug 08 '12 at 15:53
4

Cast to the return type defined by the API you are calling.

If it says it returns a List<SomeObj>, then that is. Don't try to retrieve the underlying type, because:

a) It can vary with new versions (or even between calls)

b) You do not need to know the implementing class for anything.

If you need an ArrayList, then do new ArrayList<SomeObject)(getObjs());

SJuan76
  • 24,532
  • 6
  • 47
  • 87
3

The whole point of using interfaces (List) is to hide implementation details. Why do you want to cast it to specific implementation?

Aravind Yarram
  • 78,777
  • 46
  • 231
  • 327
2

You're correct. That is not a good idea. You need to use the interface form that it's returning.

Samuel
  • 16,923
  • 6
  • 62
  • 75
1

It would throw a ClassCastException if you downcasted to ArrayList when in fact it was a LinkedList. Generally its never a good idea to downcast like this especially if you didn't write the code that returns the object you want to downcast. Plus if you are using 3rd party libs like this they might change what they return you as they improve their code. If you put downcasts like this in your code it might work today, but when you upgrade your libs it all of a sudden it breaks. And it breaks at runtime not compile time so you won't know its broken until you run it. This is an issue of you violating the contract the library has with you which only using a List interface.

chubbsondubs
  • 37,646
  • 24
  • 106
  • 138
1

The reason why it returns a List is so that you don't have to care what it is underlying that interface.

The List interface simply declares the contract the object has to satisfy, and how you query it. The library author is at liberty in the future to pick an ArrayList,a LinkedList, or maybe a LazyDatabasePopulatedList. In fact you may get a different implementation at runtime depending on how the providing class has been implemented.

So long as you have a contract to adhere to, this buys you a lot of freedom. There's a lot to be said for only talking and providing interfaces, and dealing with concrete classes as little as possible.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
1

You should always use the interface in place of the Handle. That is the whole point of OOP Languages so that you can switch between any implementation later.

If you are casting to any concrete class, the compiler will warn you about a possibility of Cast Exception that may occur. You can use SuppressWarning if you are very much sure about the type.

Byter
  • 1,132
  • 1
  • 7
  • 12
1

It's not a good idea because you don't know what implementation the method returns; if it's not an ArrayList, you'll get a ClassCastException. In fact, you should not be concerned with what exact implementation the method returns. Use the List interface instead.

If, for some reason, you absolutely need an ArrayList, then create your own ArrayList and initialize it with the List returned by the method:

ArrayList<SomeObj> myOwnList = new ArrayList(getObjs());

But don't do this, unless you absolutely need an ArrayList - because it's inefficient.

Jesper
  • 202,709
  • 46
  • 318
  • 350
1

Why don't you do this:

List<SomeObj> objs = getObjs();

And then work with that list. If for some reason you really need a ArrayList, you can always do

ArrayList<SomeObj> arrayList = new ArrayList<SomeObj>();
arrayList.addAll(objs);

And work with that. This is not very efficient though.

brimborium
  • 9,362
  • 9
  • 48
  • 76