I've got an application where I use primitive arrays and Lists for a class called Item. These are used interchangeably for legacy reasons (I also wish this was just one type, but it's the way it is).
Now I have to add a new method like this that works via a for-each loop:
public void something(Item... items) {
for (Item i : items) {
doStuff();
}
}
public void something(List<Item> items) {
for (Item i : items) {
doStuff();
}
}
In other words, exactly the same method twice for both primitive Arrays and Lists. Is there any way to nicely refactor this into a single method?
You can't shouldn't (*) do this in a single method. Item[]
and List<Item>
are unrelated types.
You should make one of the overloads call the other: either something(Item... items)
calls something(List<Item>)
, or something(List<Item>)
calls something(Item... items)
.
Of the two options, it is better for the array overload to call the list overload:
public void something(Item... items) {
something(Arrays.asList(item));
}
This is cheap, because it doesn't copy the array, but rather wraps it: creating the List
is O(1)
.
If you were to invoke the array overload from the list overload:
public void something(List<Item> items) {
something(items.toArray(new Item[0]));
}
This would be more expensive, since the toArray
call has to create and populate an array: it is an O(n)
operation, where n
is the size of the list. However, it has the slight advantage that something
would not be able to replace the contents of the List
, since any updates to the array are simply discarded after execution.
(*) You can, but it would be really gross, and not type-safe, as you'd have to accept an Object
parameter, as there is no other common super type of List<Item>
and Item[]
; and you'd still end up having to repeat the loops for the two types; and you'd have to handle the possibility of a completely unrelated type being passed in (at runtime):
public void something(Object obj) {
if (obj instanceof List) {
for (Object element : (List<?>) obj) {
Item item = (Item) element; // Potential ClassCastException.
doStuff();
}
} else if (obj instanceof Item[]) {
for (Item item : (Item[]) obj) {
doStuff();
}
} else {
throw new IllegalArgumentException();
}
}
What a mess. Thank the maker for overloads.