Why Java Can’t Have eachWithIndex (and Kotlin Can): A Deep Dive into JVM Language Design
If you’ve written Ruby, you’ve probably fallen in love with this simple pleasure:
Clean. Expressive. Zero boilerplate.
Or maybe you’ve seen the Kotlin equivalent:
Again: elegant, readable, developer-friendly.
And then… there’s Java.
Or the Streams version that always sparks debate:
At some point, every Java engineer asks:
“““
Java and Kotlin both run on the JVM.
Kotlin can make forEachIndexed it look like a real list method.
Why can’t Java just do the same? Can’t we use reflection? Proxies? Magic?
““”
This post answers that deeply and practically:
Why Ruby truly supports
each_with_indexWhy Java cannot
How Kotlin makes it look possible
What really happens inside the JVM
and what this teaches us about language design
Let’s dive in.
The Root Problem: Java Collections Aren’t Designed Like Ruby’s
Ruby treats most collections under the Enumerable abstraction, which assumes sequential iteration and indexing behavior. Methods like map, each_with_index, select, etc., are built at the language-level abstraction of “things you can iterate”.
Java, meanwhile, is much more explicit in its contract design. Collection in Java intentionally does not guarantee index semantics.
Different types mean different realities: For example, in Set, there is no guarantee of ordering, in map not concept of index.
So if Java added:
list.forEachWithIndex(...)What does “index” even mean for a HashSet? For a Map? For a sorted structure where order changes with comparator rules?
Java’s design philosophy prefers:
strong contracts
predictable semantics
no “sometimes meaningful” APIs
So Java forces you to acknowledge structure when you write code. If you want index-based iteration, you work with a List and write explicit logic.
That’s deliberate.
📢 Some of you have reached out to my email for some discounts on annual subscription. I understand that for fresh grads/students it’s hard to pay $30 per year and I would like to share an additional 40% discount ($18 per year) until Jan 31st.
If you are still experiencing financial constraints that make it challenging to pay, please email me directly, and I will look into it.
Not convinced? Check out the details of the past work
But What About Reflection? Can’t We Just “Add a Method”?
This is the most common misconception. Reflection in Java is powerful… but not that powerful.
Reflection can:
inspect fields and methods
invoke methods dynamically
read/write private fields
explore class metadata
Reflection cannot:
Add new methods to
java.util.ListModify class bytecode after load
monkey-patch JDK classes like Ruby
mutate class structure
Once List.class is loaded by the JVM, its method set is sealed. The verifier enforces strict integrity rules to maintain type safety and runtime stability.
You can get hacky though.







