High-performance array-based list using static shared storage per type. In most cases, a LinkedList is a better choice due to its flexibility. This data structure is only recommended for performance-critical code and requires careful use to avoid fragmentation.
ArrayList is faster than LinkedList for:
LinkedList is better for:
Each ArrayList
Choose wisely based on how many types you have.
PRESIZE, DON’T RESIZE Bad: new ArrayList
Why: Resize operations copy ALL elements to new memory. Expensive!
REUSE, DON’T RECREATE Bad: In loop let temp = new ArrayList<int>() ... destroy temp Good: let temp = new ArrayList<int>() ... temp.clear() in loop
Why: Allocation/Deallocation is moderately expensive and causes fragmentation
ORDERED REMOVAL IS SLOW Bad: list.removeAt(i) // O(n) - shifts all elements Good: list.removeAtUnordered(i) // O(1) - swaps with last element
Only use removeAtUnordered() if order doesn’t matter
ITERATE BY INDEX Good: for i = 0 to list.size()-1 // Zero allocation Good: list[i] // Indexing operator
ArrayList has no iterator by design - index loops keep hot paths allocation-free.
AVOID FREQUENT INSERTS AT START Bad: list.addtoStart(x) // O(n) every time Good: Use LinkedList or add in reverse order
Operation | ArrayList | LinkedList | Notes ——————-|———–|————|————————— add(elem) | O(1)* | O(1) | *O(n) on resize! addtoStart(elem) | O(n) | O(1) | Shifts all elements get(index) | O(1) | O(n) | Major ArrayList advantage removeAt(index) | O(n) | O(1) | Shifts remaining elements removeAtUnordered | O(1) | N/A | Doesn’t preserve order Iterate all | Faster | Fast | LinkedList does double the work, but is still fast Memory per element | 1 slot | 3 slots | Element + 2 pointers Create/destroy | Varies | High | AL might need memory management, LL needs to process Nodes
ArrayList uses section allocation in a shared static array per type. Destroyed lists return sections to a free pool for reuse. Reuse is first-fit and claims the whole freed section (sections are never split). Adjacent free sections are merged (compacted) when the store approaches its cap or when the free pool is full, so interior gaps may persist until then. The free pool itself is bounded (MAX_FREE_SECTIONS): if it is full and compaction cannot shrink it, a freed section’s space is dropped (it leaks until the type’s store is reset). Element references are always cleared, so this is a space leak, not a dangling-reference leak. Presize and reuse lists to avoid reaching this state.
Fragmentation occurs when lists grow - the old section becomes a gap. This is why presizing matters: growth = copy to new location = wasted space.
Hard limit (wc3 / Jass native target): the shared store is a fixed-size array, so it is bounded by JASS_MAX_ARRAY_SIZE total slots per type across all live instances; exceeding it raises an error. On the Lua target the store is a dynamically growing table, so the cap does not apply - allocateStorage branches on the magic isLua constant and skips the error. ArrayList’s added value on Lua is keeping element types static instead of relying on typecasting.
public class ArrayList<T:>
public interface ArrayListPredicate<T:>
public interface ALItrClosure<T:>
public interface ArrayListUpdater<T:>
public interface MapClosure<T:, Q:>
public interface FoldClosure<T:, Q:>
public interface Comparator<T:>
public function asArrayList<T:>(vararg T ts) returns ArrayList<T>
public function ArrayList<int>.sort()
public function ArrayList<real>.sort()
public function ArrayList<string>.sort()
public function ArrayList<string>.joinBy(string separator) returns string
Joins elements from a string list into one string using a separator
public function ArrayList<string>.join() returns string
Joins elements from a string list into one string