Saturday, 24 January 2015

Common mistakes which we do with Java Code - Part 2


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:


  1. first puzzle - Java Puzzlers - Google IO Tech Talks

Wednesday, 21 January 2015

Common mistakes which we do with Java Code - Part 1

1) Can you predict the output of the following code.


class Problem1
{
    public static void main(String[] args)
    {
        System.out.println(Boolean.getBoolean("true"));
    }
}


Predicted output:

true

Real output:

false

Analysis:

Boolean.getBoolean searches for that system property (WHAT!!!) and if that is equalIgnoreCase to "true" then only this will return true. In all cases this will return false. So, in this case the output is false.

How to overcome this?

As we use parseInt to convert String to int, parseFloat to convert String to float, we need to use parseBoolean.

System.out.println(Boolean.parseBoolean("true")) will return true.

2) What does the following program print?


class Problem2
{
    public static void main(String[] args)
    {
        long num = 10_000 * 10_000 * 10_000 * 10_000;
        System.out.println(num);
    }
}


Predicted output:

1 followed by 16 zeros.

Real output:


a negative value

Analysis:

Negative number output implies a overflow but howcome this can happen as I have used long to store this value?

Whenever we use a number, by default, it is assumed to be int. All the operations which we do on this number will be treated as int. So in this example by the time we do the 3rd multiplication the result will not fit in the int and returns a negative number.

We need to use L after the number to treat the number as long. One more glitch here is that the overflow will still happen if we put L as part of the last number. That is,
num = 10_000 * 10_000 * 10_000 * 10_000L will also overflow because by the time the compiler sees L, the result would have already overflowed.

How to overcome this?

Put L after the first number or introduce a 1L and multiply the rest of the numbers.

long num = 1L * 10_000 * 10_000 * 10_000 * 10_000;

will store num having 1 followed by 16 zeros.

3) What does the following program print?


class Problem3
{
    public static void main(String[] args)
    {
        java.util.List<Integer> ints = new java.util.ArrayList<>();
        for (int i = 1; i <= 5; i++)
        {
            ints.add(i);
        }
       
        ints.remove(3);
       
        System.out.println(ints);
    }
}


Predicted output:
[1, 2, 4, 5]

Real output:

[1, 2, 3, 5]

Analysis:

In this problem I add integers from 1 to 5 to the list and I remove 3 from the list. I expect it to print [1, 2, 4, 5]. Is this true? Think about it.

The problem is due to the introduction of autoboxing and unboxing features in JDK 5. In List I can add only Integer objects and not primitives. To make our life simpler, Java Compiler takes care of auto boxing the int value to Integer object. So, after the end of the loop we have a list with contents [1, 2, 3, 4, 5]. True. But remove is confusing. If we look at the documentation, we have 2 remove methods. One removes based on the index and other removes Objects. In our case which one will the compiler pick? As we have a method which takes an int, there is an exact match to call that method. The value 3 is treated as primitive itself and it is not autoboxed to Integer object 3. The effect is that we remove the value present at the index 3 which is 4.

How to overcome this?

ints.remove((Object) 3) will make the compiler call the remove(Object obj) method and this will return [1, 2, 4, 5].

Tuesday, 20 January 2015

SPOJ - Enormous Input and Enormous Output - Solution in Java

Today we will discuss about how to go about solving
ENORMOUS INPUT and ENORMOUS INPUT and OUTPUT problem.

The purpose of the first problem is read input as fast as possible. To be precise, we need to read 2.5MB/sec.

The second problem is to read input as fast as possible as well as output the results faster.


Problem 1 : Approach

Using BufferedReader to read the inputs.

The following solution contains nothing complicated to explain. 

a) We have used try with resources of Java 7 which takes care of closing the resource even in case of an exception. This is one of the best practices in Java 7.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 

class EnormousInput
{
    public static void main(String[] args) throws IOException
    {
        int totalNumsDivisibleByK = 0;
      
        try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in)))
        {
            int[] nAndK = getNandK(br);
            int n = nAndK[0];
            int k = nAndK[1];
            int[] allInputs = getAllInputs(br, n);
            totalNumsDivisibleByK = findTotalNumsDivisibleByK(allInputs, k);
        }
      
        System.out.print(totalNumsDivisibleByK);
    }

    private static int[] getAllInputs(BufferedReader br, int n) throws IOException
    {
        int[] allIntegers = new int[n];
        for (int i = 0; i < allIntegers.length; i++)
        {
            allIntegers[i] = Integer.parseInt(br.readLine());
        }
      
        return allIntegers;
    }

    private static int findTotalNumsDivisibleByK(int[] allInputs, int k) throws IOException
    {
        int totalNumsDivisibleByK = 0;
      
        for (int i = 0; i < allInputs.length; i++)
        {
            if (allInputs[i] % k == 0)
            {
                totalNumsDivisibleByK++;
            }
        }
        return totalNumsDivisibleByK;
    }

    private static int[] getNandK(BufferedReader br) throws IOException
    {
        int[] aNandK = new int[2];
      
        String firstLine = br.readLine();
        String[] tokens = firstLine.split("\\s+");
        int n = Integer.parseInt(tokens[0]);
        int k = Integer.parseInt(tokens[1]);
        aNandK[0] = n;
        aNandK[1] = k;
      
        return aNandK;
    }
}


This solution takes around 0.90 secs and gets accepted.


Problem 2 : Approach

Here also we use BufferedReader to read the inputs. For printing outputs we need to have a similar mechanism so that we don't spend much time in the I/O. We can use BufferedWriter. I have tried with StringBuilder to accumulate the outputs and print the final output once. 

Each outputs must be seperated by new line so I have made use of System.lineSeparator() which is available in Java 7.


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 

class EnormousInputAndOutput
{
    public static void main(String[] args) throws IOException
    {
        try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in)))
        {
            int n = Integer.parseInt(br.readLine());
           
            String output = getMultipliedValueOfEachInput(br, n);
           
            System.out.print(output);
        }
    }

    private static String getMultipliedValueOfEachInput(BufferedReader br, int n) throws IOException
    {
        StringBuilder sb = new StringBuilder();
       
        for (int i = 1; i <= n; i++)
        {
            String[] nums = br.readLine().split("\\s+");
            int num1 = Integer.parseInt(nums[0]);
            int num2 = Integer.parseInt(nums[1]);
           
            int output = num1 * num2;
           
            sb.append(output);
            sb.append(System.lineSeparator());
        }
       
        return sb.toString();
    }
}


The solution takes around 1.30 secs and gets accepted.

Wednesday, 4 September 2013

Installing i386 32 bit rpm files in amd 64 bit ubuntu

In my office, I am using ubuntu linux. But one particular piece of software developed by our company was available in msi and rpm formats. msi is microsoft installer available for windows. For linux, rpm can be used. I don't know how to install rpm files in ubuntu. After searching in web and doing some trials, I found the following steps were helpful.

1) First install Alien. This is the definition of Alien from ubuntu site. Alien converts an RPM package file into a Debian package file or Alien can install an RPM file directly. 

2) Then if the rpm is for 32 bit, you will have little bit tough time. The following steps are one way to solve this issue.
i386-32 bit rpm install on amd64 bit ubuntu (different architecture and different processing machines)

2a)    To install 32 bit apps on 64 bit ubuntu, we need to have installed "ia32-libs". The original source is here.

2b) Then we need to convert the rpm to tgz (tar.gz) format. Straightforward conversion from rpm to deb format can cause issues if the package was meant for i386 and you are trying to install in amd64 bit. It will say architecture is incompatible like "<filename.rpm> is for architecture i386 ; the package cannot be built on this system".  This is because the package is built for i386 but we are trying to install in amd 64 bit.  To overcome this, we need to first perform the conversion from rpm to tgz.
sudo alien --to-tgz <file name.rpm>

2c) The above step gives us tgz file. This can be then converted to deb format by using alien command again.
sudo alien --to-deb <filename.tgz>
Then the usual procedure to install deb  can be used. That is use "dpkg -i <file name.deb>.
 
References:

Tuesday, 27 November 2012

Java - public static final String constant vs Enum constant

Let me prove you that why we need to use as much enum as possible instead of public static final String.

Constant.java

public class Constant
{

    public static final String TEST_CONST_STRING = "TestConstString";
}


EnumConstant.java

public enum EnumConstant
{
    TEST_CONST_STRING("EnumTestConstString");

    String str;

    EnumConstant(String str)
    {
        this.str = str;
    }

    public String getValue()
    {
        return str;
    }
}


Consumer.java

public class Consumer
{
    public static void main(String[] args)
    {
        System.out.println(Constant.TEST_CONST_STRING);
        System.out.println(EnumConstant.TEST_CONST_STRING.getValue());
    }
}



Assume all the 3 java files are present in the same directory. Now do the following:

a) Run javac Constant.java EnumConstant.java Consumer.java

b) Run java Consumer
Now obviously TestConstString and EnumTestConstString gets printed in the console.

c) Now change the "TestConstString" in Constant.java to "TestConstStringChanged" and "EnumTestConstString" to "EnumTestConstStringChanged".

d) Run javac Constant.java EnumConstant.java. Don't compile Consumer.java.

e) Run java Consumer.
Now you can see that TestConstString and EnumTestConstStringChanged gets printed in the console.

TestConstStringChanged doesn't get printed.

Reason: When we change any value pointed by public static final String, then we need to recompile all the files which depend on this string. In case of Enum, we don't need to compile the dependent files.