Java’s generics type erasure has been regarded as a failure design since JDK 1.5, but I haven’t realized it until today when I run into a serious issue about it.
I’m using night-config library to parse TOML config file for my program. I parsed and stored a list of
long from TOML. Right after I got my program up and running, I noticed that
list.contains(x) failures at random numbers. Those numbers seem to exist in the list and successfully printed out, but I cannot locate the issue based on the information I got.
So I read the TOML parser it self, trying to locate where it handles Integer/Long parsing and found the function that deal with number parsing:
returns an int if it is enough to represent the value correctly
So the output list, assumptively
ArrayList<Long> typed, does consist both Integer and Long if Integer is enought to represent the value, calling
List.contains will certainly fail if you pass a long parameter to check whether the number, which is actually int, is in the collection.
Having it double-checked by using fastutil’s LongArrayList confirmed my thoughts, it fails to construct because there are int values in a marked
In this case,
ArrayList<Long> is merely a mark that give instructions for compiler to check, but it does not replace the
Object array in the list, nor does it assert runtime type-checking. The issue may absolutely be avoided or easily solved in C#, Rust and other strong-typed generics language.
Always use strong-typed fastutil or trove collections for storing primitive values.
Blame Java for it’s bad design.
In this case, cast boxed int or long values to Number and cast it back to Long, then store them in a