Open In App

5 Most Common Java Pitfalls

Improve
Improve
Like Article
Like
Save
Share
Report

1. Not understanding that String is an immutable class: 
The Java String class is immutable (Unmodifiable). This is because String objects are cached in a String pool. The object that a String is referencing to can change, but the String objects themselves cannot. 

Example: 

Java




public class Main {
    public static void main(String[] args)
    {
        String str = "GeeksFor";
        // A new string will be returned, but the actual String will remain the same
        str.concat("Geeks");
        // Prints initial value "GeeksFor"
        System.out.println(str);
        // Now we change the reference of "str" to point to the new String returned
        str = str.concat("Geeks");
        // Prints the new concatenated String
        System.out.println(str);
    }
}


Output : GeeksFor 
         GeeksForGeeks

2. Memory Leaks: 
One of the core benefits of Java is the Java Garbage Collector, which manages the objects memory on the heap. Whenever an object is unreachable it is automatically freed. 
However, a common slip for both new and experienced programmers is preventing the memory from being freed, by allowing objects to be reachable that are no longer in use. This can be a very big downside to a project since memory leaks block resources and degrades the application performance. It can even lead to java.lang.OutOfMemoryError.

Common Cases are: 

  • Static Fields Declaring a static field and forgetting to set it to null after its data is not longer needed
  • Unclosed Streams The Java Virtual Machine allocates memory for every connection opened. Forgetting to close the connection consumes memory. Such connections can be: Input Streams, Database Connections, Sessions, and others.
  • The finalize() method When we override the finalize() method, the object of that class is not any more directly garbage collected. The Garbage Collector is then waiting for finalization, which is happening at a later point in time.

3. Pre/Post Increment Operator and side-effects: 
The evaluation order of operators in Java appear to be evaluated from left to right, the side effects can be seen instantly:

Java




public class Main {
    public static void main(String[] args)
    {
        int num = 0;
        /* First case */
        // The increment operator happens after the value is pushed onto the stack and assigned
        num = num++;
        // Prints initial value
        System.out.println(num);
        /* Second case */
        // Increment occurs first, and then it is pushed to the stack and assigned to num
        num = ++num;
        System.out.println(num);
    }
}


Output : 0 
         1 

The execution context of the first case is as follows: 

  1. Store previous value of operand.
  2. Increment the value.
  3. Return the previous value

The execution context of the second case is as follows:

  1. Increment the value.
  2. Store value of operand (incremented)
  3. Return the value

4. Using the relational operator “==” for Objects comparison. 
Many novice programmers try to use the “==” operator to compare objects and when the behavior of their code is not as expected they are confused. A thing to be aware of is that the relational operator “==” is making a reference comparison, it checks if both objects point to the same location in memory. Using the .equals() method will eliminate the problem since it compares the values inside the objects.

Java




public class Main {
    public static void main(String[] args)
    {
        String s1 = new String("GeeksForGeeks");
        String s2 = new String("GeeksForGeeks");
        // Comparing using the relational operator
        if (s1 == s2) { // false
            System.out.println("Both objects point to the same memory location!");
        }
        // Comparing using the .equals()
        if (s1.equals(s2)) { // true
            System.out.println("The value inside the object instances match!");
        }
        // Declaring a string with a reference to s1
        String s3 = s1;
        if (s3 == s1) { // true
            System.out.println("Both objects point to the same memory location!");
        }
    }
}


Output : The value inside the object instances match! 
         Both objects point to the same memory location! 

Although sometimes the “==” operator will give the expected answer: 

Java




public class Main {
    public static void main(String[] args)
    {
        String s1 = "GeeksForGeeks";
        String s2 = "GeeksForGeeks";
        // Comparing using the relational operator
        if (s1 == s2) { // true
            System.out.println("The two strings are the same!");
        }
        else {
            System.out.println("The two strings are the different!");
        }
    }
}


Output : The two strings are the same! 

The reason is in the Java Language Specification String Literals: ‘Literal strings within the same class in the same package represent references to the same String object’. The condition in the code is true because the literals are consisting of the same characters.

5. Using raw types 
Before Java started using generic types, there have not been alternatives to raw types (types that are not parameterized). For backward compatibility reasons, it is still possible to define these:

Java




public class Main {
    public static void main(String[] args)
    {
        // Defining a raw list, without specifying its type parameter
        List geeksList = new ArrayList();
        // Due to the unspecified type we can add any data type and the code will compile
        geeksList.add(100);
        geeksList.add(200);
        geeksList.add("GeeksForGeeks");
        // When the second element is reached the compiler will throw a runtime error
        // because we are trying to cast a string to an integer
        geeksList.forEach(k -> System.out.println((int)k * 2));
    }
}


Output : 200
         400
Exception in thread "main" java.lang.ClassCastException: 
java.base/java.lang.String cannot be cast to java.base/java.lang.Integer

This issue can be prevented by defining the generic type of the List: 

List geeksList = new ArrayList();

Now the code won’t compile since we are trying to add a String type to a collection of Integer types. Generic Types are created for a reason and prevent programmers from nasty bugs and overheads.



Last Updated : 11 Mar, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads