Backend Development 18 min read

Common Java Development Pitfalls and Solutions

The article surveys frequent Java development mistakes—such as NullPointerExceptions, unsafe object equality, improper null handling, manual mapping errors, thread‑safety and thread‑pool misuse, swallowed exceptions, Spring bean initialization problems, memory leaks, performance traps, and transaction misconfigurations—while offering practical fixes like annotations, Optional, MapStruct, concurrent utilities, immutable wrappers, bounded executors, unified logging, and proper AOP usage.

DaTaobao Tech
DaTaobao Tech
DaTaobao Tech
Common Java Development Pitfalls and Solutions

In daily Java development we often encounter bugs such as NullPointerException (NPE), thread‑safety issues, improper exception handling, and others. This article lists common problems and practical solutions.

NullPointerException

Use JSR‑305/JetBrains annotations like @NotNull and @Nullable to let static analysis tools detect possible nulls.

Prefer Optional for chained calls:

public class OptionalExample {
    public static void main(String[] args) {
        User user = getUser();
        String city = "DEFAULT";
        if (user != null && user.isValid()) {
            Address address = user.getAddress();
            if (address != null) {
                city = address.getCity();
            }
        }
        System.out.println(city);

        Optional
optional = getUserOptional();
        city = optional.filter(User::isValid)
                .map(User::getAddress)
                .map(Address::getCity)
                .orElse("DEFAULT");
        System.out.println(city);
    }
    // ... other methods and classes
}

Object Equality

Replace a.equals(b) with Objects.equals(a, b) to avoid NPE.

Null‑Object Pattern

Return an empty collection instead of null :

public class EmptyListExample {
    public static void main(String[] args) {
        List
listNullable = getListNullable();
        if (listNullable != null) {
            for (String s : listNullable) {
                System.out.println(s);
            }
        }
        List
listNotNull = getListNotNull();
        for (String s : listNotNull) {
            System.out.println(s);
        }
    }
    @Nullable
    public static List
getListNullable() { return null; }
    @NotNull
    public static List
getListNotNull() { return Collections.emptyList(); }
}

Object Mapping

Manual conversion often leads to bugs. Using MapStruct generates type‑safe mappers at compile time:

@Mapper(componentModel = "spring",
        unmappedSourcePolicy = ReportingPolicy.ERROR,
        unmappedTargetPolicy = ReportingPolicy.ERROR)
public interface UserConvertor {
    UserDTO toUserDTO(UserDO userDO);
    // inner DTO/DO classes
}

Thread‑Safety

Prefer atomic operations such as ConcurrentHashMap.computeIfPresent instead of separate get / put calls.

public class ConcurrentHashMapExample {
    private Map
map = new ConcurrentHashMap<>();
    public void append(String key, String suffix) {
        map.computeIfPresent(key, (k, v) -> v + suffix);
    }
}

Encapsulate related fields in an immutable object and update them atomically.

@Getter
public class AtomicDiamondParser {
    private volatile Range range;
    // ...
    public void handleRange() {
        Range r = range;
        System.out.println(r.getStart());
        System.out.println(r.getEnd());
    }
    @Value
    public static class Range { private int start; private int end; }
}

Thread‑Pool Misuse

A cached thread pool can exhaust resources under load. Create a bounded pool instead:

public class ManualCreateThreadPool {
    private Executor executor = new ThreadPoolExecutor(
        10, 10, 1, TimeUnit.MINUTES,
        new ArrayBlockingQueue<>(1000),
        new ThreadFactoryBuilder().setNameFormat("work-%d").build());
}

Exception Handling

Do not swallow exceptions or lose stack traces. Use a unified AOP handler or log the full exception.

Spring Bean Implicit Dependencies

Avoid static access to ApplicationContext or reading bean fields before they are initialized. Use BeanFactoryPostProcessor with highest precedence to guarantee order.

Memory / Resource Leaks

Replace global Map caches with Guava LoadingCache that has size limits.

Performance Pitfalls

Do not use URL as map keys because its hashCode triggers DNS lookups; prefer URI . Use proper benchmarking tools such as JMH instead of ad‑hoc loops.

Spring Transaction Issues

Self‑invocation bypasses @Transactional . Call transactional methods from another bean or use AOP proxies.

References include articles on the “billion‑dollar mistake”, double‑checked locking, and latency numbers.

JavaConcurrencyException HandlingSpringBest Practicesbug
DaTaobao Tech
Written by

DaTaobao Tech

Official account of DaTaobao Technology

0 followers
Reader feedback

How this landed with the community

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