Search code examples
javaintegersetshort

Java: Different outputs when add/remove short and integer elements in a Set


I wasn't sure on how to ask this question. But, what is the different between these 2 lines of code?

Set<Integer> a = new HashSet<Integer>();
for (int i = 0; i < 100; i++) {
    a.add(i);
    a.remove(i - 1);
}

System.out.println(a.size());

I expected 99 to be the output

Output is 1


Set<Short> a = new HashSet<Short>();
for (Short i = 0; i < 100; i++) {
    a.add(i);
    a.remove(i - 1);
}

System.out.println(a.size());

I expected 99 to be the output

Output is 100


Solution

  • The type of the expression i - 1 is int because all operands in an integer arithmetic expression are widened to at least int. Set<Short> has add(Short) and remove(Object) so there's no casting/autoboxing needed on the remove call. Therefore you are trying to remove Integers from a set of Shorts.

    Note that for this reason it almost never makes sense to declare a Set<Number>:

    final Set<Number> ns = new HashSet<>();
    final short s = 1;
    ns.add(s);
    ns.add(s+0);
    ns.add(s+0L);
    System.out.println(ns); // prints [1, 1, 1]
    

    As a bonus round, if you change the set implementation to TreeSet, the magic disappears and it throws a ClassCastException, giving away the trick.

    Deep down, this issue has to do with the fact that equality is a symmetric relation, which must not distinguish the right hand side from the left hand side. These semantics are impossible to achieve with Java's single-dispatch methods.