List.toArray()

Java ima tih nekih izluđujućih momenata. Konverzija liste u niz je jedan od njih. Uobičajeni način na koji sam do sada radio bio je sledeći:

List<Foo> list;
...
Foo[] array = list.toArray(new Foo[list.size()]);

Metoda toArray() koja ne prima argument vraća Object[], a to je uglavnom beskorisno. Zato se češće koristi ova varijacija koja prima niz koji odgovara tipu koji se čuva u listi.

Implementacija ove metode je radila na sledeći način: ukoliko je predati niz iste dužine, lista se prosto ‘prespe’ u njega. U suprotnom, kreira se novi niz odgovarajuće dužine, a predati niz se prosto ignoriše. Tip i dužina niza su poznati, tako da nema problema za refleksiju. Zaključak je, dakle, da ima smisla svaki put instancirati niz tačne dužine, kako bi se izbeglo interno kreiranje novog niza i odbacivanje predatog - što zajedno daje bolje performanse i bolji utrošak memorije.

Sve je to razumljivo, osim što je baš ružno. Osim toga, ovaj kod nije ni potpuno ispravan ukoliko se lista deli kroz više niti: moguće je dodati element u listu nakon što se pročita njena veličina. Kako bilo, uvek sam ovako pisao konverziju liste u niz.

Sve dok sam, slučajno, naučio da to više nije neophodno. Preporučeni način je sledeći:

Foo[] array = list.toArray(new Foo[0]);

Kraće i konciznije, lepo. Čekaj, ali šta je sa performansama i duplim kreiranjem niza? Zar nisu narušene?

Ispostavlja se da ne. Šta više, druga varijanta je i brža! Arrays.newArray radi vrlo dobro u VM. U ovom slučaju VM i izbegava inicijalizaciju liste, jer pretpostavlja (ispravno) da će cela biti popunjena. I verovatno radi još kojekakvu optimizaciju. Kakva god da je magija iza, toArray(new T[0]) radi brže.

I to je tako već godinama unazad. Eh, čovek se uči dok je živ.