我如何重构这个循环?

时间:2017-01-27 15:11:20

标签: 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();
    }
}

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

4 个答案:

答案 0 :(得分:68)

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

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

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

public void something(Item... items) {
  something(Arrays.asList(item));
}

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

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

public void something(List<Item> items) {
  something(items.toArray(new Item[0]));
}

这会更昂贵,因为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();
  }
}
真是一团糟。感谢制造商过载。

答案 1 :(得分:17)

如果你使用Java 8,你也可以在forEach上拨打mapStream,就可以了,例如。

yourStream.forEach(doStuff());

其中doStuff()consumer处理字符串或使用yourStream.forEach(s -> doStuff())如果您不想处理字符串而只是do stuff

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

Stream.of(yourArray) // or Arrays.stream(yourArray)
      .forEach(doStuff());

并列出您的清单:

list.stream()
    .forEach(doStuff());

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

如果你真的想保留something(...)方法(能够同时处理varargs和列表),你仍然需要重载方法或使用Object self.geometry = SCNBox(width: self.size.width, height: self.size.height, length: 0.1, chamferRadius: 0) let it = SCNLookAtConstraint(target: cameraNode) it.isGimbalLockEnabled = true self.constraints = [it] } -parameter-方法。

答案 2 :(得分:1)

您可以实现单个方法,在本例中为第二个方法,因为它有一个列表作为参数。您可以使用Arrays.asList(items)转换列表中的数组,而不是第一种方法,然后可以调用第一种方法。因此,最后,您将只有一个方法(列表作为参数)。

此外,如果项目列表中的元素很少,则可以使用Java 8中的lambda表达式:

items.foreach(item -> doStuff(item));

因此,您将不会有一个只包含一个循环的方法,代码将更容易阅读。

答案 3 :(得分:0)

您应该通过在将其转换为数组后传递List来实现此目的。

将此保留为您的单一方法,

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

当你想传递List<Item>然后像这样传递时,

something(listItem.toArray(new Item[listItem.size()]))