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).
我有一个应用程序,我使用原始数组和列表称为Item。由于遗留原因,这些可以互换使用(我也希望这只是一种类型,但它就是这样)。
Now I have to add a new method like this that works via a for-each loop:
现在我必须添加一个像这样的新方法,通过for-each循环:
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?
换句话说,对于原始数组和列表,两次完全相同的方法。有没有办法很好地将它重构为一个方法?
4 个解决方案
#1
68
You can't shouldn't (*) do this in a single method. Item[]
and List<Item>
are unrelated types.
你不应该(*)在一个方法中这样做。 Item []和List
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)
.
你应该让其中一个重载调用另一个:要么(Item ... items)调用某个东西(List
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)
.
这很便宜,因为它不会复制数组,而是包装它:创建List是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.
这会更昂贵,因为toArray调用必须创建并填充数组:它是一个O(n)操作,其中n是列表的大小。但是,它有一些优点,即某些内容无法替换List的内容,因为对数组的任何更新都会在执行后被丢弃。
(*) 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):
(*)你可以,但它确实很粗糙,而且不是类型安全的,因为你必须接受一个Object参数,因为没有其他常见的超类型List
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.
真是一团糟。感谢制造商过载。
#2
16
If you use Java 8 you could also just call forEach
or map
on your Stream
and you are done, e.g.
如果你使用Java 8,你也可以在你的Stream上调用forEach或map,你就完成了,例如
yourStream.forEach(doStuff());
where doStuff()
is the consumer dealing with the String or use yourStream.forEach(s -> doStuff())
if you don't want to handle the string and just do stuff
.
doStuff()是消费者处理String或使用yourStream.forEach(s - > doStuff())如果你不想处理字符串而只是做东西。
You can obtain a stream as follows:
您可以按如下方式获取流:
Stream.of(yourArray) // or Arrays.stream(yourArray)
.forEach(doStuff());
and for your list:
并为您的清单:
list.stream()
.forEach(doStuff());
The main benefit of using the streams is probably readability. It may lose regarding performance and it may also lose if you don't want to call Stream.of/Arrays.stream
or Collection.stream()
just to obtain the stream.
使用流的主要好处可能是可读性。它可能会失去性能,如果您不想调用Stream.of / Arrays.stream或Collection.stream()来获取流,它也可能会丢失。
If you really want to keep the something(...)
method (being able to deal with both: the varargs and the list) you are still requiring an overloaded method or use Andy Turner's proposal with the Object
-parameter-method.
如果你真的想保留某些东西(...)方法(能够同时处理varargs和列表),你仍然需要重载方法或者使用Andy Turner的提议和Object-parameter-method。
#3
1
You can implement a single method, in this case, the second one because it has a list as parameter. Instead of the first method, you can convert the array in a list with Arrays.asList(items)
and then, you can call the first method. So, in the end, you will have only a single method (that has a list as parameter).
您可以实现单个方法,在本例中为第二个方法,因为它有一个列表作为参数。您可以使用Arrays.asList(items)转换列表中的数组,而不是第一种方法,然后,您可以调用第一个方法。因此,最后,您将只有一个方法(列表作为参数)。
Also, if the items list has few elements, you can use the lambda expressions from Java 8:
此外,如果items列表中的元素很少,则可以使用Java 8中的lambda表达式:
items.foreach(item -> doStuff(item));
So, you will not have a method that contains only one loop and the code will be easier to read.
因此,您将不会有一个只包含一个循环的方法,代码将更容易阅读。
#4
0
You should achieve this by passing List after converting it to array.
您应该通过在将其转换为数组后传递List来实现此目的。
Retain this as your single method,
保留这个作为你的单一方法,
public void something(Item... items) {
for (Item i : items) {
doStuff();
}
}
and when you want to pass a List<Item>
then pass like this,
当你想传递一个List
something(listItem.toArray(new Item[listItem.size()]))
something(listItem.toArray(new Item [listItem.size()]))
#1
68
You can't shouldn't (*) do this in a single method. Item[]
and List<Item>
are unrelated types.
你不应该(*)在一个方法中这样做。 Item []和List
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)
.
你应该让其中一个重载调用另一个:要么(Item ... items)调用某个东西(List
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)
.
这很便宜,因为它不会复制数组,而是包装它:创建List是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.
这会更昂贵,因为toArray调用必须创建并填充数组:它是一个O(n)操作,其中n是列表的大小。但是,它有一些优点,即某些内容无法替换List的内容,因为对数组的任何更新都会在执行后被丢弃。
(*) 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):
(*)你可以,但它确实很粗糙,而且不是类型安全的,因为你必须接受一个Object参数,因为没有其他常见的超类型List
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.
真是一团糟。感谢制造商过载。
#2
16
If you use Java 8 you could also just call forEach
or map
on your Stream
and you are done, e.g.
如果你使用Java 8,你也可以在你的Stream上调用forEach或map,你就完成了,例如
yourStream.forEach(doStuff());
where doStuff()
is the consumer dealing with the String or use yourStream.forEach(s -> doStuff())
if you don't want to handle the string and just do stuff
.
doStuff()是消费者处理String或使用yourStream.forEach(s - > doStuff())如果你不想处理字符串而只是做东西。
You can obtain a stream as follows:
您可以按如下方式获取流:
Stream.of(yourArray) // or Arrays.stream(yourArray)
.forEach(doStuff());
and for your list:
并为您的清单:
list.stream()
.forEach(doStuff());
The main benefit of using the streams is probably readability. It may lose regarding performance and it may also lose if you don't want to call Stream.of/Arrays.stream
or Collection.stream()
just to obtain the stream.
使用流的主要好处可能是可读性。它可能会失去性能,如果您不想调用Stream.of / Arrays.stream或Collection.stream()来获取流,它也可能会丢失。
If you really want to keep the something(...)
method (being able to deal with both: the varargs and the list) you are still requiring an overloaded method or use Andy Turner's proposal with the Object
-parameter-method.
如果你真的想保留某些东西(...)方法(能够同时处理varargs和列表),你仍然需要重载方法或者使用Andy Turner的提议和Object-parameter-method。
#3
1
You can implement a single method, in this case, the second one because it has a list as parameter. Instead of the first method, you can convert the array in a list with Arrays.asList(items)
and then, you can call the first method. So, in the end, you will have only a single method (that has a list as parameter).
您可以实现单个方法,在本例中为第二个方法,因为它有一个列表作为参数。您可以使用Arrays.asList(items)转换列表中的数组,而不是第一种方法,然后,您可以调用第一个方法。因此,最后,您将只有一个方法(列表作为参数)。
Also, if the items list has few elements, you can use the lambda expressions from Java 8:
此外,如果items列表中的元素很少,则可以使用Java 8中的lambda表达式:
items.foreach(item -> doStuff(item));
So, you will not have a method that contains only one loop and the code will be easier to read.
因此,您将不会有一个只包含一个循环的方法,代码将更容易阅读。
#4
0
You should achieve this by passing List after converting it to array.
您应该通过在将其转换为数组后传递List来实现此目的。
Retain this as your single method,
保留这个作为你的单一方法,
public void something(Item... items) {
for (Item i : items) {
doStuff();
}
}
and when you want to pass a List<Item>
then pass like this,
当你想传递一个List
something(listItem.toArray(new Item[listItem.size()]))
something(listItem.toArray(new Item [listItem.size()]))