Inconsistent Operation Widen Rules in Java
Join the DZone community and get the full member experience.
Join For FreeWhen you perform a unary or binary operation in Java the standard behaviour is to use the widest operand (or a wider one for byte, short and char). This is simple to understand but can be confusing if you consider what the optimal type is likely to be.
Multiplication
When you perform multiplication, you often get a much large number than either of the individual numbers in magnitude. i.e. |a*b| >> |a| and |a*b| >> |b| is often the case. And for small types this works as expected
Consider this program
public static void main(String[] args) throws IOException { System.out.println(is(Byte.MAX_VALUE * Byte.MAX_VALUE)); System.out.println(is(Short.MAX_VALUE * Short.MAX_VALUE)); System.out.println(is(Character.MAX_VALUE * Character.MAX_VALUE)); System.out.println(is(Integer.MAX_VALUE * Integer.MAX_VALUE)); System.out.println(is(Long.MAX_VALUE * Long.MAX_VALUE)); } static String is(byte b) { return "byte: " + b; } static String is(char ch) { return "char: " + ch; } static String is(short i) { return "short: " + i; } static String is(int i) { return "int: " + i; } static String is(long l) { return "long: " + l; }
int: 16129 int: 1073676289 int: -131071 int: 1 long: 1
Only byte * byte and short * short doesn't overflow as these have been widened. char * char isn't a meaningful operation even though it is allowed. But int * int does overflow even though we have a long type which could store this value without an overflow. Both byte and short are widened implicitly but not int. longshould really be widened but we don't have a wider primitive type, which would have made sense once upon a time however a 64-bit primitive doesn't seem so long these days.
Division
System.out.println(is(Byte.MAX_VALUE / (byte) 1)); System.out.println(is(Byte.MAX_VALUE / (short) 1)); System.out.println(is(Byte.MAX_VALUE / (char) 1)); System.out.println(is(Byte.MAX_VALUE / (int) 1)); System.out.println(is(Byte.MAX_VALUE/ (long) 1));
prints
int: 127 int: 127 int: 127 int: 127 long: 127
Modulus
System.out.println(is(Byte.MAX_VALUE % Byte.MAX_VALUE)); System.out.println(is(Byte.MAX_VALUE % Short.MAX_VALUE)); System.out.println(is(Byte.MAX_VALUE % Character.MAX_VALUE)); System.out.println(is(Byte.MAX_VALUE % Integer.MAX_VALUE)); System.out.println(is(Byte.MAX_VALUE % Long.MAX_VALUE)); System.out.println(is(Byte.MAX_VALUE % (byte) 2)); System.out.println(is(Short.MAX_VALUE % (byte) 2)); System.out.println(is(Character.MAX_VALUE % (byte) 2)); System.out.println(is(Integer.MAX_VALUE % (byte) 2)); System.out.println(is(Long.MAX_VALUE % (byte) 2));
int: 0 int: 127 int: 127 int: 127 long: 127 int: 1 int: 1 int: 1 int: 1 long: 1
Negation
System.out.println(is(-Byte.MIN_VALUE)); System.out.println(is(-Short.MIN_VALUE)); System.out.println(is(-Character.MIN_VALUE)); System.out.println(is(-Integer.MIN_VALUE)); System.out.println(is(-Long.MIN_VALUE));
int: 128 int: 32768 int: 0 int: -2147483648 long: -9223372036854775808
System.out.println(is(+Byte.MIN_VALUE)); System.out.println(is(+Short.MIN_VALUE)); System.out.println(is(+Character.MIN_VALUE)); System.out.println(is(+Integer.MIN_VALUE)); System.out.println(is(+Long.MIN_VALUE));
int: -128 int: -32768 int: 0 int: -2147483648 long: -9223372036854775808
Can we fix this?
long i = ... byte b = ... long l = i % b + Integer.MAX_VALUE;
Conclusion
Published at DZone with permission of Peter Lawrey, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments