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开发者_JAVA技巧 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.
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.
Why not just declare method as a private void doSomething(final ArrayList<T> list)
, if you want only ArrayList as parameter?
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.
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.
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
.
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.
Your first method changes the List
passed to the method while the other one doesn't. Two methods are not comparable.
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.
精彩评论