Interesting Behaviours of Java

Patric Steiner · November 16, 2019

There is a famous video that showcases some weird “features” of JavaScript. If you haven’t seen it, I highly recommend to check it out. It’s hilarious (and a bit frustrating at the same time).

Java is a much stricter language than JavaScript, but there are still some, let’s say “not-so-obvious”, behaviours you can encounter in Java. So let’s get to it.

Negative + negative = positive?

Let us start with an easy one:

int negativeNumber = -2147483648;
int absoluteValue = Math.abs(negativeNumber);
System.out.println(absoluteValue > 0); // false.

In fact, absoluteValue is equal to negativeNumber. negativeNumber is equal to -2^31, which is the smallest possible number to represent in an int. When you negate that, you get 2^31. However, the largest possible number that an int can represent is 2^31-1, therefore 2^31 will roll over to -2^31. The reason for that is that most computers use the Two’s Complement to represent numbers.

Integer vs. int - easy

This one is also not too surprising:

Integer a = new Integer(1);
Integer b = new Integer(1);
Integer c = 1;
System.out.println(a >= b); // true
System.out.println(a <= b); // true
System.out.println(a == b); // false
System.out.println(a == c); // false

Because there is no <= or >= operator, the compiler auto un-boxes the Integers to primitive ints and the comparison works as expected. The == operator exists on Integer though (inherited from Object), compares the two integers by reference and therefore return false. c is automatically boxed to Integer, therefore the previous statement applies.

Wait, not so easy after all?

This next one is a bit more confusing at first:

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false
Integer e = 128;
int f = 128;
System.out.println(e == f); // true
int g = 128;
int h = 128;
System.out.println(e == f); // true

The JVM caches all Integer values from -128 to 127 at the start, therefore a and b have the same reference.

🧙 Casting Integers

Object o = (Integer) null; // ok (redundant cast)
int i = (Integer) null; // nullpointer exception

The cast itself is successful, but the auto un-boxing tries to call .intValue(), which obviously throws a nullpointer exception.

The ternary operator as a shorthand for if-else

Object a = true ? new Integer(1) : new Double(2.0);
Object b;
if (true) b = new Integer(1); 
else b = new Double(2.0);
System.out.println(a); // 1.0
System.out.println(b); // 1

The ternary operator has one type only! Therefore it is in fact not an exact alternative to if-else

Variable names in Java

We all know the rules of varibale names in Java. They can start with a letter, _ oder $. Also the names must be unique in the same scope. But guess what:

String _ = "This";
String _ = "actually";
String _‎‏ = "compiles!";
System.out.println(_+_+_‎‏); // This actually compiles!

Wait, what?! But Java doesn’t allow redeclaration of a variable! True. I tricked you. But Java does allow hidden characters in variable names ;) I used \u200e and \u200f here.