5 Most Common Java Pitfalls

  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:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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 inital 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);
        }
    }

    chevron_right

    
    

    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:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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);
        }
    }

    chevron_right

    
    

    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 behaviour 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.

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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!");
            }
        }
    }

    chevron_right

    
    

    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:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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!");
            }
        }
    }

    chevron_right

    
    

    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 parametrized). For backward compatibility reasons, it is still possible to define these:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    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));
        }
    }

    chevron_right

    
    

    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.



My Personal Notes arrow_drop_up

Vice-President at the Computing Society of Edinburgh Napier University Likes investing time in geeky topics as well as sharing knowledge and making connections

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.




Article Tags :
Practice Tags :


2


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.