2016-07-30 5 views
0

Immer wenn Collection#addAll aufgerufen wird, erstellt es eine Kopie der Argumentliste und hängt es dann an die Sammlung an, auf der addAll aufgerufen wurde.Problem mit addAll-Methode

Unten ist der Code für Fall I:

 if (parentData != 0) { 
      if (nodeParentMap.get(parentData) != null) { 
       nodeParentMap.put(newNodeData, parentData); 
       //Creates new Nodes' parent and assigns its next to its parent, in that way I get the parents' linked list 
       Node parent = Node.build(parentData); 
       parent.next = parentListMap.get(parentData); 

       parentListMap.put(newNodeData, parent); 
      } 
     } else { 
      //Code for root 
      nodeParentMap.put(newNodeData, parentData); 
      parentListMap.put(newNodeData, null); 
     } 

Hier seine N Iterationen nimmt Nth parent zu finden.

Unten ist der Code für Fall II:

 if (parentData != 0) { 
      if (nodeParentMap.get(parentData) != null) { 
       nodeParentMap.put(newNodeData, parentData); 

       //Here all the parents of a node are present in arrayList #parents, 
       //so that I can fetch parent in O(1) as I know the index 
       ArrayList<Integer> parents = new ArrayList<>(); 
       parents.add(parentData); 
       parents.addAll(parentListMap.get(parentData)); 

       parentListMap.put(newNodeData, parents); 
      } 
     } else { 
      //Code for root 
      nodeParentMap.put(newNodeData, parentData); 
      parentListMap.put(newNodeData, new ArrayList<>()); 
     } 

Aber im Fall II, wenn Arraylist # addAll genannt wird, es Kopie der Liste erstellt geführt und dann attatches es. Also, gibt es eine Möglichkeit, ArrayList#addAll mit dem Aufruf System#arrayCopy auszuführen?

Vielen Dank.

+0

Warum denkst du mit 'addAll' eine Kopie der Argumentliste? – Mureinik

+0

@Mureinik In Oracle JDK tut es wirklich. Die Implementierung der ArrayList konvertiert zuerst die angegebene Auflistung in ein Array und hängt dann die Array-Elemente an ihren eigenen internen Speicher an. –

Antwort

1

Im Allgemeinen sollten Sie sich nicht kümmern. Der Unterschied wird nicht wahrnehmbar sein, wenn Sie diesen Code nicht millionenfach ausführen. Sie sollten Ihren Code so sauber wie möglich schreiben, wenn möglich, und Ihre Absicht zeigen. Haben Sie ein Leistungsproblem? Haben Sie Ihren Code profiliert und der Profiler hat Ihnen gezeigt, dass Sie viel Zeit mit dem Kopieren der Array-Elemente verbringen?

Messen, nicht raten. Sie müssen wissen, dass ein Problem vorliegt. Und Sie müssen wissen, ob es nach einem Codewechsel verschwunden ist.

Können Sie vielleicht Ihren Algorithmus ändern, wenn es so viele doppelte Daten und so viel Elementkopieren gibt, dass Sie vielleicht eine effizientere Struktur oder einen effizienteren Algorithmus verwenden könnten? Zum Beispiel könnten Sie Iterables.concat() von Google Guava verwenden. Der resultierende Code wird kürzer, sagt Ihre Absicht sehr sauber aus und kopiert nichts - das zugrundeliegende List wird einen Verweis auf die ursprüngliche Datenstruktur enthalten und wird es nur träge bekommen. Vorsicht, wenn das massiv verkettet ist, hast du dir nicht wirklich geholfen ...

Wenn du nach alldem immer noch denkst, dass du die Double-Array-Kopie sowieso vermeiden musst, was hindert dich daran?

List<Integer> tempParents = parentListMap.get(parentData); 
List<Integer> parents = new ArrayList<>(tempParents.size() + 1); 
parents.add(parentData); 
for (Integer i : tempParents) { 
    parents.add(i); 
} 

Beachten Sie, dass Performance-weise, dieser Code vergleichbar allgemein sein wird, nur addAll() Aufruf da in der überschriebenen Umsetzung der Arraylist von addAll() gibt es keine Iteration nur schwer Array Kopieren, die in der JVM intrinsified und hoch optimierte . Die obige Version wird daher nur für kurze Listen (wahrscheinlich) oder zur Lösung eines Speicherproblems nützlich sein, nicht für eine Performance, da die iterative Version keinen zusätzlichen temporären Speicher benötigt, während das Kopieren von addAll() dies tut.