我如何重构这个循环?

Sel*_*lbi 47 java refactoring

我有一个应用程序,我使用原始数组和列表称为Item.由于遗留原因,这些可以互换使用(我也希望这只是一种类型,但它就是这样).

现在我必须添加一个像这样的新方法,通过for-each循环:

public void something(Item... items) {
    for (Item i : items) {
        doStuff();
    }
}

public void something(List<Item> items) {
    for (Item i : items) {
        doStuff();
    }
}
Run Code Online (Sandbox Code Playgroud)

换句话说,对于原始数组和列表,两次完全相同的方法.有没有办法很好地将它重构为一个方法?

And*_*ner 69

应该(*)在一个方法中这样做.Item[]并且List<Item>是不相关的类型.

您应该让其中一个重载调用另一个:something(Item... items)调用something(List<Item>)something(List<Item>)调用something(Item... items).

在这两个选项中,最好是数组重载调用列表重载:

public void something(Item... items) {
  something(Arrays.asList(item));
}
Run Code Online (Sandbox Code Playgroud)

这很便宜,因为它不会复制数组,而是包装它:创建Listis O(1).

如果要从列表重载调用数组重载:

public void something(List<Item> items) {
  something(items.toArray(new Item[0]));
}
Run Code Online (Sandbox Code Playgroud)

这会更昂贵,因为toArray调用必须创建并填充数组:它是一个O(n)操作,其中n是列表的大小.但是,它具有something无法替换内容的轻微优点List,因为对数组的任何更新都会在执行后被丢弃.


(*)你可以,但它确实很粗糙,而且不是类型安全的,因为你必须接受一个Object参数,因为没有其他常见的超类型List<Item>Item[]; 而且你最终还是要为这两种类型重复循环; 并且您必须处理传递完全不相关类型的可能性(在运行时):

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

真是一团糟.感谢制造商过载.

  • @ user3216060 [Javadoc to the rescue](https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#asList(T ...)):"返回固定大小由指定数组支持的列表.(对返回列表的更改"直写"到数组.)此方法充当基于数组的API和基于集合的API之间的桥梁". (7认同)
  • @ user3216060"因为**不复制**数组," - 开销相当小. (2认同)

Rol*_*and 18

如果你使用Java 8,你也可以打电话forEach或打电话map给你Stream,你也完成了,例如

yourStream.forEach(doStuff());
Run Code Online (Sandbox Code Playgroud)

这里doStuff()消费者处理字符串或使用yourStream.forEach(s -> doStuff()),如果你不想处理字符串和公正do stuff.

您可以按如下方式获取流:

Stream.of(yourArray) // or Arrays.stream(yourArray)
      .forEach(doStuff());
Run Code Online (Sandbox Code Playgroud)

并为您的清单:

list.stream()
    .forEach(doStuff());
Run Code Online (Sandbox Code Playgroud)

使用流的主要好处可能是可读性.它可能会失去性能,如果您不想打电话Stream.of/Arrays.streamCollection.stream()只是获取流,它也可能会丢失.

如果你真的想保持something(...)方法(能够同时处理:在可变参数和列表),你仍然需要一个重载的方法或用安迪·特纳的建议Object-parameter法.