Inspect the cost at the actual call boundary
On JVM, primitive-specialized arrays, generic collections, lambdas, and value classes can have different allocation behavior. Nullable or generic usage can require boxing even when a value class avoids a wrapper elsewhere.
fun primitiveTotal(values: IntArray): Long {
var total = 0L
for (value in values) total += value
return total
}
fun genericTotal(values: List<Int>): Long = values.sumOf { it.toLong() }
Both return the same result, but their storage representations differ. Do not choose a representation solely from a microbenchmark that ignores the rest of the application's API and conversion costs.
Inlining may remove callback overhead while increasing generated code size. Inspect bytecode and allocations when a measured hotspot warrants it. On Android, use appropriate benchmark tooling and realistic release configurations.
Exercise
Benchmark equivalent workloads with an IntArray and List<Int>, excluding input construction when measuring traversal, then include construction in a separate measurement.
Check: report input size, runtime, warmup, allocation, and output equivalence; a single stopwatch result is insufficient.