The JLS is a good reference, and makes the requirement for type promotion clear, but no one has talked about the essential question.
At the machine level (post JIT compilation or down deep in the JVM), a processor with a 64-bit ALU will be likely to do the 64- to 32-bit comparison with one instruction to sign-extend the 32-bit operand and a second to do the 64-bit wide comparison followed by a branch around the doStuff
call.
For the int
to int
32-bit comparison, the sign extension can be omitted. So the difference is one instruction or one cycle for modern cores.
If the machine has a 32-bit ALU, then the 64-bit comparison probably requires 4 instructions: compare, branch, test, branch. But it might be done in 3 (sub with borrow, sub, branch) with the right instructions and/or an extra register.
The int
to int
requires two: compare and branch. So the difference is 1 or 2 instructions/cycles.
There are very few programs where 1 or 2 cycles make a meaningful performance difference. Use the type you need to ensure your program will work under all contingencies you can imagine over the next decade or so. Forget the couple of cycles.
NB Where 64-bits actually cause a meaningful performance hit is inflating data structure (and to a lesser extent code) sizes by a factor of 2 so that cache and page misses become more frequent. But again you should not worry about this in advance.
Unfortunately Java makes it impossible to alias the unboxed types. A change from int
to long
or float
to double
and back is non-trivial: a serious language flaw in many situations.