1). Can you predict what the program will print?
public class Problem1
{
public static void main(String[] args)
{
int[] arr = new int[] {1, 2, 3, 4, 5};
for (int i = 0; i < arr.length; i++)
{
arr[i] = arr[i] * arr[i];
}
System.out.println(arr);
}
}
Predicted Output:
[1, 4, 9, 16, 25]
Real output:
something like [I@5df9cdda
Analysis:
Array is an object. It’s toString is defined as “Returns a string consisting of the name of the class of which the object is an instance, the at-sign character @, and the unsigned hexadecimal representation of the hash code of the object.”
In our case the array is an int and arr.getClass() returns class [I and here the class name is [I , followed by @, followed by the hashcode of the array.
How to overcome this:
Use java.util.Arrays.toString, for printing 1D arrays. If the array contains objects which are instances of your application, then it is a must you need to override toString implementation. If not, in your logs you might see some output like the above one.
Make it a habit to override toString implementation which will also be useful during debugging of the Java programs.
2) Can you predict what the program will print?
class Problem2
{
public static void main (String[] args)
{
//0x01FF is the unicode representation of ǿ.
char c = 0x01FF;
byte[] bytes = String.valueOf(c).getBytes();
System.out.println(java.util.Arrays.toString(bytes));
}
}
Predicted output:
a) [-57, -65] b) [63] c) it depends d) none of the above
Expected output:
it depends. on utf 8 machines, it prints (a) and on win 7 32 bit machines it prints (b).
Analysis - What is the problem
Java, by default, takes the charset of the machine (where we run the program) when we call getBytes of the string, read/write to/from a Input/OutputStream, if we have not mentioned the charset explicitly. This causes different behavior across platforms.
How to overcome this
If any API has any overloaded method which takes encoding, go ahead and use this. It is recommended to explicitly mention the encoding/charset even if the string contains simple English characters. This makes the scope clearer for the reader about the details of the String. If we have not mentioned the encoding there are 2 possible cases. The string either contains simple English characters (or) the developer had forgotten to mention the encoding.
Recommended APIs
Till Java 6 there was a need for us to mention the encoding as a String. That is we need to hardcode “UTF-8” or “UTF-16”. I usually faced a doubt about which String is valid. That is “utf8” or “utf-8” or “UTF8” or “UTF-8” and so on. Every time there was a need for me to go to the internet to check which one is correct as there is some room for confusion. Thankfully in Java 7 we have StandardCharSets. This makes it easy for the developers to write the correct code in the first place.
Files (has bunch of static methods to work with files).
Must Read Article
3) Can you predict what the program will print? (Taken from Java Puzzlers but slightly modified)
import java.math.BigDecimal;
class Problem3
{
public static void main (String[] args)
{
BigDecimal costOfApple = new BigDecimal(0.3);
BigDecimal costOfOrange = new BigDecimal(0.6);
BigDecimal totalCost = costOfApple.add(costOfOrange);
System.out.println(totalCost);
}
}
Expected Output:
0.9
Real Output:
0.899999999999999966693309261245303787291049957275390625
Analysis:
We know that we should not use float/double for money calculations as it might not yield correct value. We have used BigDecimal yet we have hit an issue. First let us look at the doc of new BigDecimal(double). Point 1 explains in detail why we are seeing the issue. It says,
“new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625”.
Only addition/multiplication combinations of (½) and its powers alone can be represented exactly. For example 0.5 can be represented exactly in the computers. To verify, you can write a program which prints new BigDecimal(0.5) which will print out 0.5, but new BigDecimal(0.2), new BigDecimal(0.4) won’t exactly print the same values.
Assigning double variable with value of 0.2, 0.4 will print these values exactly. This is because while printing the value, JVM takes care of printing only exact decimal digits to differentiate from the floating point number below from it and the floating point number above from it. They don’t print all the digits. BigDecimal exposes the problem clearly.
How to overcome this
By using BigDecimal’s String constructor. That is, new BigDecimal(“0.4”) will both store and print the value as 0.4.
References: