我如何重构这个循环?
我有一个应用程序,我使用原始数组和名为Item的类。 这些可以交换使用的原因(我也希望这只是一种types,但它的方式)。
现在我必须添加一个像这样的新方法,通过for-each循环来工作:
public void something(Item... items) { for (Item i : items) { doStuff(); } } public void something(List<Item> items) { for (Item i : items) { doStuff(); } }
换句话说,对于原始数组和列表,两次完全相同的方法。 有没有什么办法很好地重构这一个单一的方法?
你不能不应该(*)以单一的方法做到这一点。 Item[]
和List<Item>
是不相关的types。
你应该让其中一个重载调用另一个:任何something(Item... items)
调用something(List<Item>)
,或者something(List<Item>)
调用something(Item... items)
。
在这两个选项中,最好是数组重载调用列表重载:
public void something(Item... items) { something(Arrays.asList(item)); }
这是便宜的,因为它不复制数组,而是包装它:创buildList
是O(1)
。
如果您要从列表重载调用数组重载:
public void something(List<Item> items) { something(items.toArray(new Item[0])); }
这将会更加昂贵,因为toArray
调用必须创build并填充数组:这是一个O(n)
操作,其中n
是列表的大小。 然而,它有一个小优点,就是something
无法replaceList
的内容,因为对数组的任何更新都会在执行后被丢弃。
(*)你可以 ,但是这将是非常严重的,而不是types安全的,因为你不得不接受一个Object
参数,因为没有其他常见的超types的List<Item>
和Item[]
; 而你仍然不得不重复这两种types的循环; 你必须处理一个完全无关的types(在运行时)的可能性:
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(); } }
真是一团糟。 感谢制造商超载。
如果你使用Java 8,你也可以调用forEach
或者在你的Stream
上map
,例如
yourStream.forEach(doStuff());
doStuff()
是消费者处理String的地方,或者如果你不想处理这个string,只需要do stuff
你可以使用yourStream.forEach(s -> doStuff())
。
您可以获得一个stream如下:
Stream.of(yourArray) // or Arrays.stream(yourArray) .forEach(doStuff());
和你的名单:
list.stream() .forEach(doStuff());
使用stream的主要好处是可读性。 如果不想调用Stream.of/Arrays.stream
或Collection.stream()
来获取stream,则性能可能会Stream.of/Arrays.stream
。
如果你真的想保留something(...)
方法(能够处理可变参数和列表),你仍然需要一个重载的方法,或者使用Andy Turner的scheme和Object
参数方法。
您可以实现一个单一的方法,在这种情况下,第二个,因为它有一个列表作为参数。 您可以使用Arrays.asList(items)
将列表中的数组转换为第一个方法,然后调用第一个方法。 所以,最后,你将只有一个方法(有一个列表作为参数)。
另外,如果项目列表中的元素很less,则可以使用Java 8中的lambdaexpression式:
items.foreach(item -> doStuff(item));
所以,你不会有一个只包含一个循环的方法,而且代码会更容易阅读。
在将List转换为数组之后,您应该通过传递List来实现此目的。
保留这个作为你的单一方法,
public void something(Item... items) { for (Item i : items) { doStuff(); } }
当你想传递一个List<Item>
然后像这样传递,
something(listItem.toArray(new Item[listItem.size()]))