Top 10 Java Coding Mistakes Every Developer Should Avoid in 2025

    Top 10 Java Coding Mistakes Every Developer Should Avoid in 2025

    Avoid common Java pitfalls that cause bugs, performance issues, and security risks. Discover the top 10 Java coding mistakes with examples and best practices to write clean, efficient, and reliable code in 2025. Perfect for beginners and experienced Java developers.

    default profile

    Munaf Badarpura

    August 18, 2025

    6 min read

    Java is a powerful and widely-used programming language for building robust applications. However, even experienced developers can fall into common pitfalls that lead to bugs, performance issues, or security vulnerabilities. Knowing these mistakes and how to avoid them can significantly improve your code quality, it reduce debugging time, and make your applications more reliable.

    So in this article, I will explain the top 10 must-know Java coding mistakes that every Java developer should be familiar with, along with example code snippets. So let’s get started.

    1. Comparing Strings with == Instead of equals()#

    I’ve seen this mistake trip up many beginners in my projects. Using == checks for reference equality, not content equality, which can lead to unexpected results when comparing strings from different sources. It’s a common bug that causes logical errors, especially in conditions like user input validation.

    Always use the equals() method for string comparisons. For case-insensitive checks, use equalsIgnoreCase().

    Example of bad code:

    String str1 = "hello"; String str2 = new String("hello"); if (str1 == str2) { System.out.println("Equal"); // This won't print }

    Example of good code:

    String str1 = "hello"; String str2 = new String("hello"); if (str1.equals(str2)) { System.out.println("Equal"); // This will print }

    2. Not Checking for Null Before Accessing Objects#

    NullPointerException is one of the most frequent runtime errors I encounter. It happens when you try to call a method or access a field on a null reference, crashing your program unexpectedly. I personally make it a habit to add null checks early to prevent these crashes in production.

    Use conditional checks or Java’s Optional class to handle potential null values safely.

    Example of bad code:

    String name = null; int length = name.length(); // Throws NullPointerException

    Example of good code:

    String name = null; if (name != null) { int length = name.length(); } else { System.out.println("Name is null"); }

    Or using Optional:

    Optional<String> optionalName = Optional.ofNullable(null); int length = optionalName.map(String::length).orElse(0);

    3. Modifying a Collection While Iterating Over It#

    I’ve debugged this issue countless times — it leads to ConcurrentModificationException when you add or remove elements from a list during iteration with a for-each loop. This mistake disrupts the iterator and can cause unpredictable behavior in multi-threaded environments.

    Use an Iterator explicitly and call its remove() method, or collect changes in a separate list and apply them after iteration.

    Example of bad code:

    List<String> list = new ArrayList<>(Arrays.asList("apple", "banana", "cherry")); for (String fruit : list) { if (fruit.equals("banana")) { list.remove(fruit); // Throws ConcurrentModificationException } }

    Example of good code:

    List<String> list = new ArrayList<>(Arrays.asList("apple", "banana", "cherry")); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String fruit = iterator.next(); if (fruit.equals("banana")) { iterator.remove(); } }

    4. Using Floating-Point Types for Monetary Calculations#

    In financial apps I’ve worked on, using float or double for money leads to precision errors due to binary representation, causing rounding issues like 0.1 + 0.2 != 0.3. This can result in incorrect calculations and serious business problems.

    Use BigDecimal for precise decimal arithmetic, especially for currency.

    Example of bad code:

    double amount = 0.1 + 0.2; System.out.println(amount); // Prints 0.30000000000000004

    Example of good code:

    BigDecimal amount = new BigDecimal("0.1").add(new BigDecimal("0.2")); System.out.println(amount); // Prints 0.3

    5. Not Closing Resources Like Streams or Connections#

    Forgetting to close file streams or database connections is a mistake I made early in my career, leading to resource leaks, file handle exhaustion, or OutOfMemory errors. It’s especially problematic in long-running applications.

    Use try-with-resources (introduced in Java 7) to automatically close resources.

    Example of bad code:

    FileInputStream fis = new FileInputStream("file.txt"); int data = fis.read(); fis.close(); // Might be forgotten or skipped on exception

    Example of good code:

    try (FileInputStream fis = new FileInputStream("file.txt")) { int data = fis.read(); } // Automatically closes fis

    6. Ignoring the Importance of Overriding equals() and hashCode()#

    When using custom objects in collections like HashSet or HashMap, not overriding these methods causes issues because the default implementation uses object references, leading to duplicates or failed lookups. I recommend always overriding them together for consistency.

    Override both methods, using tools like IDE generators for boilerplate.

    Example of bad code (without override):

    public class Person { private String name; // Constructor and getters... } Set<Person> set = new HashSet<>(); set.add(new Person("Alice")); set.add(new Person("Alice")); // Adds duplicate because references differ

    Example of good code (with override):

    public class Person { private String name; // Constructor and getters... @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name); } }

    7. Creating Unnecessary Objects in Loops#

    I’ve optimized performance in loops by avoiding this — creating objects like new String or Integer inside tight loops wastes memory and triggers frequent garbage collection. This reduces efficiency, especially in high-performance code.

    Reuse objects or move creation outside the loop when possible.

    Example of bad code:

    for (int i = 0; i < 1000000; i++) { String s = new String("test"); // Unnecessary new object each time // Use s... }

    Example of good code:

    String s = "test"; // Created once outside for (int i = 0; i < 1000000; i++) { // Use s... }

    8. Using Raw Types Instead of Generics#

    Raw types (like List without ) bypass type safety, leading to ClassCastExceptions at runtime and making code harder to maintain. I suggest using generics from the start for compile-time checks.

    Always specify type parameters in collections to avoid raw types mistake.

    Example of bad code:

    List list = new ArrayList(); list.add("string"); list.add(123); String s = (String) list.get(1); // Throws ClassCastException

    Example of good code:

    List<String> list = new ArrayList<>(); list.add("string"); // list.add(123); // Compile-time error String s = list.get(0);

    9. Off-by-One Errors in Loops or Arrays#

    This classic mistake, like indexing from 1 instead of 0 or using <= in loops, causes ArrayIndexOutOfBoundsException or misses elements. I double-check loop bounds in every array operation to avoid it.

    Remember arrays are 0-indexed; use < length for loops to avoid this mistake.

    Example of bad code:

    int[] arr = {1, 2, 3}; for (int i = 0; i <= arr.length; i++) { System.out.println(arr[i]); // Throws ArrayIndexOutOfBoundsException at i=3 }

    Example of good code:

    int[] arr = {1, 2, 3}; for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); }

    10. Not Handling Exceptions Properly#

    Swallowing exceptions with empty catch blocks or printing stack traces without action hides errors, making debugging tough and leaving issues unresolved. In production apps I’ve built, proper handling prevents silent failures.

    Log exceptions meaningfully, rethrow if needed, or use custom exceptions for better error handling.

    Example of bad code:

    try { int x = 1 / 0; } catch (ArithmeticException e) { // Empty catch - error is swallowed }

    Example of good code:

    try { int x = 1 / 0; } catch (ArithmeticException e) { System.err.println("Division by zero: " + e.getMessage()); // Or rethrow: throw new RuntimeException("Math error", e); }

    Conclusion#

    These 10 Java coding mistakes are essential for every Java developer to recognize and avoid. They support you throughout the development lifecycle from writing clean code to debugging, optimizing, and maintaining reliable applications.

    Want to Master Spring Boot and Land Your Dream Job?

    Struggling with coding interviews? Learn Data Structures & Algorithms (DSA) with our expert-led course. Build strong problem-solving skills, write optimized code, and crack top tech interviews with ease

    Learn more
    Java
    Java coding mistakes
    Java best practices
    Java beginner mistakes
    Java tips and tricks 2025

    Subscribe to our newsletter

    Read articles from Coding Shuttle directly inside your inbox. Subscribe to the newsletter, and don't miss out.

    More articles