Fundamentals 14 min read

13 Common Java Pitfalls You Might Be Falling Into

This article enumerates thirteen frequent Java mistakes—from returning null and misusing string concatenation to improper synchronization and lock handling—showing the flawed code, explaining why it is problematic, and providing concise, correct alternatives with runnable examples.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
13 Common Java Pitfalls You Might Be Falling Into

1. Introduction

Even experienced Java developers can slip into common errors caused by misunderstandings of language features, unfamiliarity with libraries, or rushed development. Issues such as poor memory management, misuse of exceptions, incorrect collection handling, and concurrency bugs are highlighted.

2. Real‑world examples

2.1 Nulls and Optionals

Wrong: Returning null from a method can trigger a NullPointerException.

public String getName() {
    // TODO
    return null;
}

Correct: Return an Optional<String> to make null handling explicit.

public Optional<String> getName() {
    // TODO
    String value = ... ;
    return Optional.ofNullable(value);
}

2.2 Number‑to‑String conversion

Wrong: Using the + operator for concatenation creates unnecessary objects.

public String stringConcat() {
    double pie = 3.14;
    return "" + pie;
}

Correct: Use String.valueOf for conversion, which avoids extra object creation.

public String stringConcat() {
    double pie = 3.14;
    return String.valueOf(pie);
}

2.3 Array copying

Wrong: Manually copying elements with a loop is inefficient for large arrays.

public void copyArray() {
    int[] source = {1,2,3,4,5,6};
    int[] target = new int[source.length];
    for (int i = 0, len = source.length; i < len; i++) {
        target[i] = source[i];
    }
}

Correct: Use Arrays.copyOf for a concise, performant copy.

public void copyArray() {
    int[] source = {1,2,3,4,5,6};
    int[] target = Arrays.copyOf(source, source.length);
}

2.4 Empty checks

Wrong: Using size() or length() to test emptiness reduces readability.

public void collectionEmpty(List<String> datas, String str) {
    if (datas.size() == 0) { /* TODO */ }
    if (str.length() == 0) { /* TODO */ }
}

Correct: Use isEmpty(), which is O(1) and clearer.

public void collectionEmpty(List<String> datas, String str) {
    if (datas.isEmpty()) { /* TODO */ }
    if (str.isEmpty()) { /* TODO */ }
}

2.5 Avoiding ConcurrentModificationException

Wrong: Removing elements from a list while iterating with a foreach loop throws ConcurrentModificationException.

public void loopCollection(List<String> datas) {
    for (String data : datas) {
        if ("a".equals(data)) {
            datas.remove(data);
        }
    }
}

Correct: Iterate with an Iterator and call its remove() method, or use removeIf (Java 8+).

public void loopCollection(List<String> datas) {
    Iterator<String> it = datas.iterator();
    while (it.hasNext()) {
        String data = it.next();
        if ("a".equals(data)) {
            it.remove();
        }
    }
}

// Java 8 alternative
public void loopCollection(List<String> datas) {
    datas.removeIf(data -> data.equals("a"));
}

2.6 Pre‑compiling regular expressions

Wrong: Compiling a regex at runtime each time it is used harms performance.

public void runtimeCompiling() {
    String str = "Hello, Pack";
    if (str.matches("Hello.*")) {
        // TODO
    }
}

Correct: Compile the pattern once and reuse it.

private final Pattern PATTERN_1 = Pattern.compile("Hello.*");
public void preCompiling() {
    String str = "Hello, Pack";
    if (PATTERN_1.matcher(str).matches()) {
        // TODO
    }
}

2.7 Unnecessary existence checks

Wrong: Checking containsKey before get adds redundant code.

public void calcElement(Map<String, Double> data) {
    if (data.containsKey("pack")) {
        Double value = data.get("pack");
        // TODO
    }
}

Correct: Retrieve the value directly and test for null.

public void calcElement(Map<String, Double> data) {
    Double value = data.get("pack");
    if (value != null) {
        // TODO
    }
}

2.8 Collection‑to‑array conversion

Wrong: Supplying a pre‑sized array to toArray forces an extra allocation.

public String[] collectionToArray(List<String> data) {
    return data.toArray(new String[data.size()]);
}

Correct: Pass an empty array; the method will allocate the correctly sized one internally.

public String[] collectionToArray(List<String> data) {
    return data.toArray(new String[0]);
}

2.9 Using default methods in interfaces

Wrong: Adding a new method to an interface forces all implementors to change.

interface Logger {
    void log(String message);
}

static class FileLogger implements Logger { /* ... */ }
static class ConsoleLogger implements Logger { /* ... */ }

Correct: Declare the new method as a default method, providing a default implementation.

interface Logger {
    void log(String message);
    default void error(String message) {
        System.err.printf("Error: %s%n", message);
    }
}

2.10 Modern date‑time API

Wrong: Using the legacy java.util.Date API, which is mutable and largely deprecated.

public void operatorDate() {
    Date date = new Date();
    // TODO
}

Correct: Use the Java 8+ java.time classes, which are immutable and thread‑safe.

public void operatorDate() {
    LocalDate date = LocalDate.now();
    LocalTime time = LocalTime.now();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    // TODO
}

2.11 Specifying generic types

Wrong: Declaring raw collections leads to mixed‑type elements and runtime errors.

public void genericUse() {
    List data = new ArrayList();
    data.add("abc");
    data.add(123);
}

Correct: Declare the generic type to enforce compile‑time type safety.

public void genericUse() {
    List<String> data = new ArrayList<>();
    data.add("abc");
}

2.12 Visibility in the JVM memory model

Wrong: A non‑volatile field updated by one thread may not be visible to another, causing stale reads.

public class SharedResource {
    private boolean flag = false;
    public void setFlag(boolean flag) { this.flag = flag; }
    public boolean getFlag() { return flag; } // may read stale value
}

Correct: Mark the field volatile or use synchronized blocks to guarantee visibility.

public class SharedResource {
    private volatile boolean flag = false;
    public void setFlag(boolean flag) { this.flag = flag; }
    public boolean getFlag() { return flag; }
}

Example showing a thread waiting for flag to become true will terminate only when volatile is used.

SharedResource resource = new SharedResource();
new Thread(() -> { while (!resource.getFlag()) {} }, "T1").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> { resource.setFlag(true); }, "T2").start();

2.13 Incorrect lock handling

Wrong: Placing lock.unlock() inside the try block means an exception can prevent the lock from being released, causing deadlock.

private final Lock lock = new ReentrantLock();
public void business() {
    try {
        lock.lock();
        // TODO
        lock.unlock();
    } catch (Exception e) {
        // TODO
    }
}

Correct: Acquire the lock before the try block and release it in a finally clause.

public void business() {
    lock.lock();
    try {
        // TODO
    } catch (Exception e) {
        // TODO
    } finally {
        lock.unlock();
    }
}

These patterns should be memorised to avoid subtle concurrency bugs.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavavolatileOptionalReentrantLockConcurrentModificationExceptionPatternjava.timeJava21
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.