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.
-
Why are you passing it as final? this should be causing you errors.MadMurf– MadMurf2010年02月18日 23:45:09 +00:00Commented Feb 18, 2010 at 23:45
-
3Marking an argument as final just means you cannot re-use that variable, that is assign it a new value. You can still use and modify (through method call, etc.) the value.David– David2010年02月18日 23:53:16 +00:00Commented Feb 18, 2010 at 23:53
-
1@MadMurf you're welcome. I got that piece of info in the same way you just did :DDavid– David2010年02月19日 00:28:08 +00:00Commented Feb 19, 2010 at 0:28
-
2Why do you want to call trimToSize? What if the object being passed in doesn't have a trimToSize method?Steve Kuo– Steve Kuo2010年02月19日 00:36:02 +00:00Commented Feb 19, 2010 at 0:36
-
For C developers its best to think of final here as a 'int * const foo' as opposed to a 'int const * foo'. You can't change what the pointer points to, but you can modify the target of the pointer. See en.wikipedia.org/wiki/Const-correctnessTano– Tano2010年02月19日 00:39:57 +00:00Commented Feb 19, 2010 at 0:39
8 Answers 8
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.
Comments
Why not just declare method as a private void doSomething(final ArrayList<T> list), if you want only ArrayList as parameter?
7 Comments
List as an argument, but he needs an ArrayList within the method body for a different reason (implementation-specific)List if it requires an ArrayListList. 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.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.
Comments
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.
Comments
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:
- We need to act on a series of values
- 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.
Comments
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.
Comments
Your first method changes the List passed to the method while the other one doesn't. Two methods are not comparable.
Comments
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.