tags:

views:

157

answers:

8

hi,

considering i have a method which gets a List passed as an param. Within this method i want to use for instance an ArrayList specific function on that list (lets say trimToSize()). What would be the general approach to deal with a problem like this ? Here two example:
First approach (i don't think this is good)

private void doSomething(final List<T> list) {
  // ... do something
  ((ArrayList<T>) list).trimToSize();
  // ... do something
}

Second approach (i think this one is better)

private void doSomething2(final List<T> list) {
final List<T> myList = new ArrayList<T>();
// Collections.copy(myList, list); or
myList.addAll(list);
((ArrayList<T>) myList).trimToSize();
//..do something
}

I'm curious whats the best solution for a problem like this.

+6  A: 

Why not just declare method as a private void doSomething(final ArrayList<T> list), if you want only ArrayList as parameter?

splix
He wants to be able to accept a `List` as an argument, but he needs an `ArrayList` within the method body for a different reason (implementation-specific)
David
@David, then it makes no sense for the method to accept a `List` if it requires an `ArrayList`
matt b
@mattb: What I mean is that at the API level he wants this method to be able to accept any `List`. With the *current* implementation he has chosen his logic uses an `ArrayList`. The API should not be tied to the implementation as the implementation should be free to change. The fact that one type inherits the other is just a coincidence which is causing the confusion. Logically the 2 lists (the `List` and the `ArrayList`) are separate and just happen to contain the same entries.
David
If he wants it to accept any List then the only methods he should be calling internally in the function on the passed in object are those define in the List interface. Otherwise he's leaving himself open to errors when a non-ArrayList object is passed.
MadMurf
David is right, my goal would be to provide the List type at API level and internally use a diffrent one (maybe i should have made the example methods public to be clearer sorry)
kukudas
@kukudas - The API level is not relevant since it is a private method. Other programmers won't see the method anyway.
Robin
The API is tied to the implementation. It even does a cast. You're just causing a disaster waiting to happen if anything changes since the API advertises it takes a List but internally it assumes it is an ArrayList. Either specialize the method so it takes an ArrayList, or don't have it assume what gets passed in is an ArrayList
nos
+12  A: 

Well, the preferred option is to just write the method to take an ArrayList in the first place. If you need ArrayList specific functionality, the method has no business taking a List. Transfer the responsibility of ensuring that the parameter is of the right type to the caller and don't fiddle around with it inside the method.

Chinmay Kanchi
Touche (15 chars)
Software Monkey
+2  A: 

The second we have huge overhead with big lists, but is safer. I would go for the first, but with check whether the provided List is ArrayList and then make a cast.

You should have a strong reasons to not take an ArrayList as a parameter though.

anthares
Your right i thought about bad performance too.
kukudas
+3  A: 

If you're accepting any object implementing the List interface then your function should only invoke methods implemented from the interface.

If you want to invoke functions from ArrayList class then have ArrayList as your parameter. Much safer than either of your options.

MadMurf
+2  A: 

The first option you've shown only works for ArrayLists so it's not an option if you want to support any type of List. If you want to support any type of List you must convert (not cast) it to an ArrayList.

I think there might be some confusion because the List and ArrayList are so closely related (by inheritance). It is only coincidence that the parameter type and the class we need to call the function on are related in this way.

If we abstract the requirements a bit:

  1. We need to act on a series of values
  2. We need to use trimToSize() on the series of values.

If the values were coming as an array there would be no question but to create a new ArrayList with the values from the array and then use trimToSize(), because casting would not be an option. It is just bad luck that the method we need trimToSize() happens to be on a subclass of List, and the author wants to pass the values as a List.

David
+2  A: 

What about

private void doSomething(final List<T> list) {
    final ArrayList<T> arrayList;
    if (list instanceof ArrayList) {
        arrayList = (ArrayList<T>) list;
    } else {
        arrayList = new ArrayList<T>(list);
    }
            ...
    arrayList.trimToSize();
}

Of course, I agree with Chinmay Kanchi: for a private method, it makes no sense to accept a more general type than necessary. My approach is only feasible if it causes no problems to modify the given list.

Frank Meißner
+1  A: 

Your first method changes the List passed to the method while the other one doesn't. Two methods are not comparable.

fastcodejava
A: 

Since it is a private method, the convention of using the List interface is not overly important. There is no public API affected so use whichever method is the most convenient for its usage in the class.

For example, if 5 other methods call this method with potentially varying types of List, then use your second option and centralize the conversion in 1 method (you can even throw in a check for type and not convert if you like). If your class only deals with ArrayList internally anyway, and you know that is what it will be when called, then declare it as a ArrayList and make your life easy for yourself.

Robin