46 votes

Comment puis-je refactoriser cette boucle?

J'ai une application dans laquelle j'utilise primitive des tableaux et des Listes pour une classe appelée Élément. Ceux-ci sont utilisés de façon interchangeable pour des raisons d'héritage (je tiens aussi c'était juste un type, mais c'est la façon dont il est).

Maintenant, je dois ajouter une nouvelle méthode comme ce qui fonctionne via une boucle for-each:

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

public void something(List<Item> items) {
    for (Item i : items) {
        doStuff();
    }
}

En d'autres termes, exactement la même méthode deux fois pour les deux primitives des Tableaux et des Listes. Est-il possible de bien refactoriser ce dans une seule méthode?

70voto

Andy Turner Points 13883

Vous ne pouvez pas ne devriez pas (*) le faire dans une seule méthode. Item[] et List<Item> sont sans rapport avec les types.

Vous devriez faire une des surcharges appel de l'autre: soit something(Item... items) des appels something(List<Item>)ou something(List<Item>) des appels something(Item... items).

De ces deux options, c'est mieux pour le tableau de surcharge pour appeler la liste de surcharge:

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

Ce n'est pas cher, car il ne copie pas le tableau, mais plutôt l'enveloppe: la création de l' List est O(1).

Si vous étiez à invoquer le tableau de surcharge à partir de la liste de surcharge:

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

Ce serait plus cher, puisque l' toArray appel a pour créer et remplir un tableau: c'est un O(n) , où d' n est la taille de la liste. Cependant, il a le léger avantage que something ne serait pas en mesure de remplacer le contenu de l' List, depuis les mises à jour de la matrice sont tout simplement jetés après l'exécution.


(*) Vous pouvez, mais il serait vraiment brut, et non pas de type sûr, que vous devez accepter un Object paramètre, comme il n'y a aucune autre commune de la super type d' List<Item> et Item[]; et que vous souhaitez toujours avoir à répéter les boucles pour les deux types; et vous en aurez pour gérer la possibilité de complètement différent type de cours passé (à l'exécution):

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

Quel gâchis. Remercier le créateur pour les surcharges.

17voto

Roland Points 8368

Si vous utilisez Java 8, vous pourriez tout aussi bien appeler forEach ou map sur votre Stream et vous sont effectués, par exemple

yourStream.forEach(doStuff());

doStuff() est la consommation de traiter avec la Chaîne ou de l'utilisation yourStream.forEach(s -> doStuff()) si vous ne voulez pas gérer la chaîne et juste do stuff.

Vous pouvez obtenir un flux comme suit:

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

et pour votre liste:

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

Le principal avantage d'utiliser le flux est probablement la lisibilité. Il peut perdre ce qui concerne la performance, et il peut aussi perdre si vous ne souhaitez pas appeler Stream.of/Arrays.stream ou Collection.stream() juste pour obtenir le flux.

Si vous voulez vraiment garder à l' something(...) méthode (que l'on peut gérer à la fois: les varargs et de la liste) vous avez encore besoin d'une méthode surchargée ou de l'utilisation Andy Turner proposition avec l' Object-paramètre de la méthode.

1voto

eve2017 Points 11

Vous pouvez mettre en œuvre une méthode unique, dans ce cas, le second parce qu'il a une liste en paramètre. Au lieu de la première méthode, vous pouvez convertir le tableau dans une liste avec Arrays.asList(items) et ensuite, vous pouvez appeler la première méthode. Donc, en fin de compte, vous n'avez qu'une seule méthode (qui a une liste en paramètre).

Aussi, si la liste des objets a quelques éléments, vous pouvez utiliser les expressions lambda à partir de Java 8:

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

Ainsi, vous n'aurez pas une méthode qui ne contient qu'une seule boucle et le code sera plus facile à lire.

0voto

jack jay Points 2202

Vous devriez obtenir cela en passant de la Liste après l'avoir convertie à la matrice.

Conserver ce que votre méthode unique,

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

et lorsque vous souhaitez passer un List<Item> puis passer comme cela,

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X