ââAs we all know, there is no system that works perfectly⊠never mind, Java is that kind of system too. Every system has his own crutches, errors and unexpected shutdowns (sometimes without explaining the reason, yeah, iPhone users, I am talking about you!).
ââToday we will talk about Java pitfalls, corner cases and traps.
ââTo be honest, I was inspired by the Joshua Bloch & Neal Gafter book to write this article, Java Puzzlers: Traps, Pitfalls, and Corner Cases. I was reading it and got an idea that this can be not only interesting to read, but also worth sharing.
Oddity check
ââThe first situation that I would like to explain, itâs about the oddity check.
ââHow do we usually check if a number is odd? Easy, if the division by 2 gives us a remainder of 1, then the number is odd, isnât it? Below is the method that does this.
[code language=”java” firstline=”0″]
public static boolean isOdd(int i){
return i % 2 == 1;
}
public static void main(String[] args){
System.out.println(isOdd(11));
System.out.println(isOdd(-11));
}
[/code]
ââAfter running this code, hereâs what we will see in the output:
[code language=”java” firstline=”0″]
>>>> true
>>>> false
[/code]
ââWait, what?
ââUnfortunately, it doesnât work as we expected it to. This method returns a wrong answer one quarter of the time. Why one quarter? Because half of all int values are negative, and the isOdd method fails for all negative odd values. It returns false when invoked on any negative value, whether even or odd.
ââLetâs dig deeper, how does Java remainder operator work?
ââa - ( (a/b) * b ) == a
ââOkay. How can we fix it? Letâs see…
[code language=”java” firstline=”0″]
public static boolean isOdd(int i){
return i % 2 != 0;
}
[/code]
ââNow, running that code again will give us the following output:
[code language=”java” firstline=”0″]
>>>> true
>>>> true
[/code]
ââItâs fixed, we are brilliant!
Decimal place accuracy
ââAll right, letâs move on! Imagine you are on your way home from a volleyball game and suddenly one of your carâs headlights burned out. Sad. You stop at the closest gas station to buy a new one. Luckily they cost only $1.10 and you got $2 bill. So you expect to get your 90 cents back.
[code language=”java” firstline=”0″]
public static void main(String[] args){
System.out.println(2.00 – 1.10);
}
[/code]
ââAfter executing the code above we get this:
[code language=”java” firstline=”0″]
>>>> 0.8999999999999999
[/code]
ââHmm, it doesnât look good? You were too naive to expect 0.90 in this article. Anyway, how could it know that you wanted two digits after the decimal point?
ââIf you wouldâve read about the rules of converting double values to strings, which are specified in the documentation of Double.toString() method, you would know that the program prints the shortest decimal fraction sufficient to distinguish the double value from its nearest neighbor, with at least one digit before and after the decimal point. The problem is that the number 1.1 canât be represented exactly as a double, so it is represented by the closest double value. More generally, the problem is that not all decimals can be represented accurately using binary floating-point.
ââOne of the solutions is to use printf:
[code language=”java” firstline=”0″]
System.out.printf(“%.2f%n”, 2.00 – 1.10);
[/code]
ââAnother option would be to make use of BigDecimals:
[code language=”java” firstline=”0″]
System.out.println(new BigDecimal(“2.00”).
subtract(new BigDecimal(“1.10”)));
[/code]
ââRegardless of what you will choose, youâll get your 0.90 cents.
Division of large numbers
ââNext case! Have you ever had to divide two really big numbers, for instance to divide the amount of microseconds in a day by the amount of milliseconds in a day? I guess not, but imagine there is a task to code that or you are doing it just for fun.
ââAs far as we have already covered two pitfalls, we are sure that weâll do it right this time. At least we hope soâŠ
ââWe write a nice, clean and really straightforward code.
[code language=”java” firstline=”0″]
public static void main(String[] args){
final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}
[/code]
ââThe output that we are expecting is 24 hours/day · 60 minutes/hour · 60 seconds/minute · 1,000 milliseconds/second · 1,000 microseconds/millisecond divided by amount of miliseconds. So, we are expecting 1000 but it printsâŠ
[code language=”java” firstline=”0″]
>>>> 5
[/code]
ââAgain???
ââSo, what exactly went wrong? The problem is that MICROS PER DAY does overflow. We are multiplying all int values.
ââHow can we fix it?
[code language=”java” firstline=”0″]
public static void main(String[] args){
final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
final long MILLIS_PER_DAY = 24L * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}
>>>> 1000
[/code]
ââYeah, got it now (notice the L next to 24).
String concatenation
ââHereâs another situation, tricky but not less interesting â itâs all about concatenation!
ââLetâs say we would like to check if the length of two strings is equal (why not?) Okay, now we feel really confident, we know about AT LEAST four Java traps. Letâs do it!
[code language=”java” firstline=”0″]
public static void main(String[] args){
final String firstString= “length: 10”;
final String secondString= “length: ” + firstString.length();
System.out.println(“Strings are equal: ” + firstString == secondString);
}
[/code]
ââWhat are we expecting?
[code language=”java” firstline=”0″]
>>>> Strings are equal: false
[/code]
ââOf course they are not, but waitâŠ
[code language=”java” firstline=”0″]
>>>> false
[/code]
ââWhatâs wrong this time? The + operator, whether used for addition or string concatenation, binds more tightly than the == operator.
ââSo, the rule for string concatenation is : âalways parenthesize non-trivial operandsâ.
ââHow to fix it? Check it out!
[code language=”java” firstline=”0″]
System.out.println(“Strings are equal: ” + (firstString == secondString));
>>>> Strings are equal: false
[/code]
ââWe did it again!
Working with Integer.MAX_VALUE
ââDo you remember what Integerâs max value is? Or maybe something around it? So you are being really careful right now writing a smart piece of code that will find this number, here we go:
[code language=”java” firstline=”0″]
public static final int END = Integer.MAX_VALUE;
public static final int START = END – 10;
public static void main(String[] args){
for(int i = START; i <= END; i++)
System.out.println(i);
}
[/code]
ââAnd what do we expect? Right â 2147483638, 2147483639, 2147483640 etc.!
ââBut… it looks like this code wonât stop and will loop forever or until you wonât kill it. Whatâs the problem? The thing is that the loop continues as long as the loop index i is less than or equal to Integer.MAX_VALUE, but all int variables are always less than or equal to Integer.MAX_VALUE. It is, after all, defined to be the highest int value in Java. When it reaches Integer.MAX_VALUE and performs the incrementation, it silently wraps around to Integer.MIN_VALUE.
ââHow can we fix it? Take a look:
[code language=”java” firstline=”0″]
for(long i = START; i <= END; i++)
System.out.println(i);
>>>> 2147483638
2147483639
2147483640
2147483641
2147483642
2147483643
2147483644
2147483645
2147483646
2147483647
[/code]
ââAmazing, we are awesome!
ââNow you know that you have to be really careful and check your code several times before saying with certainty that it works correctly. Sometimes these little hidden âbugsâ might make your program work unexpectedly and cause you trouble later on.
ââHope you enjoyed it!


