Java Programming Mistakes

people make


21 Jan 2017 View Comments
#java #mistake #programming #computer

There are a couple of items I would like to go over to understand fully on some of the areas we developers make mistakes. I have personally made a couple of mistakes introduced here and I thought I would write a post about them. If you are interested in coding in Java, I would at least skim through the list. Let’s start!

Convert Array to ArrayList

I have seen at least few people do this which is alright unless you are manipulating the size of the array.

List<String> list = Arrays.asList(arr);

This will create the java.util.Arrays.ArrayList, instead of java.util.ArrayList. They are slightly different. java.util.Arrays.ArrayList is fine to use when you are using operations like contains, get, set, etc.

However, if you are manipulating the size of the list, such operation as add or remove operation, the operations would not be available.

You would want to do the following instead:

List<String> arrayList = new ArrayList<String>(Arrays.asList(arr));

From my experiences, there were not many cases where you had to modify a List size for Arrays.asList. However, this is certainly a good to know.

Contains usage from the list

I have seen some people doing this in order to run contains operation within a List:

Set<String> set = new HashSet<String>(Arrays.asList(arr));
System.out.println(set.contains(targetValue));

At this point, you might as well just loop the list and find a matching data which would be O(n) worst time complexity operation. You can do this easier with the same time complexity by doing:

Arrays.asList(arr).contains(targetValue);

This is pretty much the same thing as using the loop. Searching here would also be O(n), but it’s simpler and there is definitely a gain on the space complexity since we do not need to make an extra set do handle this.

Removing an element from ArrayList

Common tries that people to do remove elements from a List to delete all items by iterating through the List:

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
for (int i = 0; i < list.size(); i++) {
    // ... operations ... //
    list.remove(i);
}
System.out.println(list);

Above will show [b, d] as a result, which is not entirely correct because my intention was to remove all the elements in the array.

This is because when list items are being removed, index of those items also changes at the same time. remove(0) would have restructured array for items in between index 1-3 which would become index 0-3 now and size decrement to 3 from 4 and it continues which would eventually remove every other element and for loop ends when i < list.size().

If a user used a foreach loop (introduced in JDK 1.5) instead like this:

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
for (String c : list) {
    // ... operations ... //
    list.remove(c);  // remove using String vs index in the previous example
}
System.out.println(list);

Above will fail at the compiling stage with a checked exception, ConcurrentModificationException, because one is trying to modify the size of a data structure which is being used to loop. Hmm.. then how should we iterate the List and remove all items?

There is still another way to modify the elements and yet deleting the entire items in the List, using the iterator:

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String x = iter.next();
    // ... operations ... //
    iter.remove();
}
System.out.println(list);

Now above code block will iterate and delete every element in the list and show, []. It is basically only using hasNext() instead of using its size() or indexOf operations.

Raw type collection

In the previous Blog Post, I had covered on Java Generics. Like I mentioned in the previous post, generics were introduced in JDK 1.5.0. Ever since then, it is not recommended to write a Raw typed object in programming Java, especially when you are dealing with any Java Collections.

Let’s take a look at an example of Raw Type:

public static void add(List list, Object o){
    list.add(o);
}
public static void main(String[] args){
    List<String> list = new ArrayList<String>();
    add(list, 10);
    String s = list.get(0);
}

As you can see clearly, there is no type enforced in the List parameter in add function although the type is given in the input in the main method.

Your Modern IDE (with JDK 1.5.0 or higher) might give you a suggestion to Generify this for reasons. When you execute the above code, you will face a runtime exception called “ClassCastException” because 10 is not a String.

Let’s make a little tweak to the code:

public static void main(String args[]) {
    List<String> list = new ArrayList<String>();
    add(list, "10");  // Change from int 10 to String "10"
    String s = list.get(0);
    System.out.println(s);
}

It will work fine and output 10 on screen. This is okay as you used a correct Data type. Java will run this without any runtime exception.

Note compile exception (checked) vs runtime exception (unchecked, ClassCastException). We can genericfy this and make changes to the function parameter which would make that unchecked exception to a checked one.

This will give us a huge benefit. Now, instead of finding out about an error at the runtime in production, you can catch at the compile stage.

Here is where Generics will help for the Raw type object:

public static void add(List<String> list, Object o){
    list.add(o);
}
public static void main(String[] args){
    List<String> list = new ArrayList<String>();
    add(list, 10);
    String s = list.get(0);
}

Just changing the List list to List<String> list, you won’t be able to compile this code anymore which then you will fix this error and then deliver your code with confidence!

“” vs new String(…)

This is another area people often misunderstand their usage. Let’s look at what I mean below, should be self descriptive:

String a = "abcd";
String b = "abcd";
System.out.println(a == b);  // True
System.out.println(a.equals(b)); // True
 
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d);  // False
System.out.println(c.equals(d)); // True

Modern IDE (with JDK 1.5.0 or higher) will probably generate a warning and suggest to use equals instead. My recommendation on this is to always use equals even when comparing Strings. Basically differences between == vs equals is that former is comparing the reference vs the latter compares the actual value. I can only assume what happened inside Java. It’s got the exact same hashcode first and second “abcd” which means that they are pointing to the same thing inside memory and treating them both equally.

Just keep in mind, when Object is being compared, == refers to references comparison. If you wanted to values to be compared via hashCode. You use equals instead. Remember to override hashCode if you override equals so as not to “break the contract”.

Operators

Developers are often confused on basics, operators in Java. Here is list of operators supported in Java.

Arithmetic operators
Arithmetic operators
Bitwise operators
Bitwise operators
Relational operators
Relational operators
Java order of operations
Java order of operations

Above Java order of operations have the top, being the highest precedence to the bottom, being the most lowest precedence. Ternary operators have the same precedence as Unary ones.

++x vs x++

Another common mistake Java developers make. This is really a question of logic.

++x increments the value of variable x before processing the current statement.

x++ increments the value of variable x after processing the current statement.

Code Example:

1
2
3
4
5
6
7
8
9
public static void main(String[] args){
    int x = 1;
    int i = ++x;
    System.out.print(i + " ");
    System.out.print(x + " ");
    i = x++;
    System.out.print(i + " ");
    System.out.print(x + " ");
}

the output of 2 2 3 3 would be incorrect, instead 2 2 2 3 is the correct one because if you look at line #6, with x++ example, x is assigned to i before x is incremented.

Code comments

Oh, where should I begin this topic …

Let me start with a story. There was a guy on my team a while ago. He one day asked what a piece of code is doing. And when I went to my desk I immediately ran a git blame and traced version history. Guess what? It was himself who wrote it. It wasn’t something like he just made a minor space change to a line that caused him to show. It was him from the beginning. The next day at the standup, he would explain what had happened that the piece of codes was indeed his and explained to the people around why he had it written the way it is.

What happened here? He could have written a reference to why he did it in such a way.

Rule of thumbs on writing comments: Comments are for whys not for whats.

Confusion over passing by value, and passing by reference

One of the developers was wondering if Java is pass-by-value or pass-by-reference. I told him Java is always pass-by-value

Well, you probably heard this before, “primitives are passed by value, objects are passed by reference”. This is a non-sense. Maybe it could be true in a Programming Language like C. I have never heard/used a language working in this way, though.

In a language like Perl, you can make anything a reference.

Let me start with this example:

Using pass-by-value in Perl:

my $scalar = "this is a scalar";
my @array = qw( this is my array );
my %hash = (
    'this' => 'my',
    'hash' => 'mine',);

print_all($scalar, @array, %hash);

Above example will treat %hash to a plain array (listed with key/value). This is not ideal because, in order to make it into a hash from the receiving side, there will be ugly operations to support it.

So it is important to use a reference to show exactly what it is like below which IMO will clear things up:

Using pass-by-reference in Perl:

my $scalar = "this is a scalar";
my @array = qw( this is my array );
my %hash = (
    'this' => 'my',
    'hash' => 'mine',);

print_all(\$scalar, \@array, \%hash);

And this is perfectly normal in Perl world. In above example, I referenced even primitive to show you that it is possible. Chances are there isn’t a good reason to reference primitives unless you really wish to manipulate with referenced variable.

In Java, we do not have an option to create such reference. Basically, Java is always pass-by-value.

Here is an example that illustrates why Java is pass-by-value:

public static void main( String[] args ){
    String aString = new String("name"); // creating an explicit string object, just for the presentation.
    say(aString);

    if (aString.equals("name")) {    //true
        System.out.println( "Java passes by value." );

    }

    if (aString.equals("changename")) {
        System.out.println( "Java passes by reference." );
    }
}

public static void say(String d) {
    Validate.isTrue(d.equals("name"));

    d = new String("changename");
    Validate.isTrue(d.equals("changename"));
}

Above example would print Java passes by value. Simply Java is passing a copy of the reference as a value to the method.

We can twist this slightly. Let’s consider this example:

public static void main( String[] args ){
    AtomicBoolean aBoolean = new AtomicBoolean(false);
    say(aBoolean);

    if (!aBoolean.get()) {
        System.out.println( "Java passes by value." );
    }

    if (aBoolean.get()) {    // true
        System.out.println( "Java passes by reference." );
    }
}

public static void say(AtomicBoolean iAmBoolean) {
    Validate.isTrue(!iAmBoolean.get());

    iAmBoolean.set(true);
    Validate.isTrue(iAmBoolean.get());
}

Above example would print, Java passes by reference.. What is going on? So here is what happened step by step:

  1. method say is called and copied aBoolean’s value of a reference and passes to the method.
  2. method say received the parameter hence there is a local copy of aBoolean called iAmBoolean.
  3. Remember reference to the object is still the same reference point. So by setting the variable inside an object did not change its memory location, but just the value within the location.

Let me show you further changes to above example below:

public static void main( String[] args ){
    AtomicBoolean aBoolean = new AtomicBoolean(false);
    System.out.println(System.identityHashCode(aBoolean)); // line added to see whereabout
    say(aBoolean);

    if (!aBoolean.get()) {
        System.out.println( "Java passes by value." );
    }

    if (aBoolean.get()) {   /// true
        System.out.println( "Java passes by reference." );
    }
}

public static void say(AtomicBoolean iAmBoolean) {
    System.out.println(System.identityHashCode(iAmBoolean)); // line added to see whereabout
    Validate.isTrue(!iAmBoolean.get());

    iAmBoolean.set(true);
    Validate.isTrue(iAmBoolean.get());
}

I basically added identityHashCode which will provide a numerical representation of the heap pointer address of the object. You will find that they are both identical.

The output on my machine:

824318946
824318946
Java passes by reference.

Let’s use the first example I showed earlier with the String and add some identityHashCode around it:

public static void main( String[] args ){
    String aString = new String("name"); // creating an explicit string object, just for the presentation.
    System.out.println("Original Before: \t" + System.identityHashCode(aString));
    say(aString);
    System.out.println("Original After: \t" + System.identityHashCode(aString));

    if (aString.equals("name")) { //true
        System.out.println( "Java passes by value." );
    }

    if (aString.equals("changename")) {
        System.out.println( "Java passes by reference." );
    }
}

public static void say(String d) {
    Validate.isTrue(d.equals("name")); // true
    System.out.println("Passed In Before: \t" + System.identityHashCode(d));

    d = new String("changename");
    System.out.println("Passed In After: \t" + System.identityHashCode(d));
    Validate.isTrue(d.equals("changename")); // true
}

The output on my machine:

Original Before:    596512129
Passed In Before:   596512129
Passed In After:    87285178
Original After:     596512129
Java passes by value.

String by default is an immutable hence I cannot do something like d.setName("changename"). However, if this is allowed, it would be similar to the example I showed above.

The important point I am bringing to the table is that Java passes a copied reference to the variable. They are essentially dealing with the same thing.

In above example, you are basically resetting a String into totally another String which would give a new memory location to a new local variable.

Share this post

Me

I am a passionate software developer working in Downtown, Vancouver. I strongly believe in art of algorithms and together with it to write clean and efficient software to build awesome products. If you would like to connect with me, choose one from below options :) You can also send me an email at