16 Essential Java Coding Habits Every Developer Should Master

This article compiles sixteen classic Java coding habits—from self‑testing changes and validating method parameters to handling resources, avoiding runtime errors, and ensuring thread‑safety and cache consistency—providing practical guidance that helps prevent most non‑business bugs.

ITPUB
ITPUB
ITPUB
16 Essential Java Coding Habits Every Developer Should Master

1. Self‑test after code changes

Run tests after any code modification, even a single variable or configuration line, to catch regressions early.

2. Validate method parameters

Check that inputs are not null and meet length or format expectations; unvalidated parameters often cause low‑level bugs such as database insert errors.

If a varchar(16) column receives a 32‑character string without validation, the insert will throw an exception.

3. Preserve compatibility when modifying old interfaces

When extending an existing public API, maintain backward compatibility to avoid deployment failures. For example, add a new parameter to a Dubbo interface while keeping the old signature functional.

void oldService(A, B) { newService(A, B, null); }
void newService(A, B, C);

4. Add clear comments for complex business logic

While good naming reduces the need for comments, intricate business code should be accompanied by concise explanations to aid future maintenance.

5. Close I/O streams

Unclosed streams waste system resources; always close them in a finally block or use try‑with‑resources (Java 7+).

FileInputStream fdIn = null;
try {
    fdIn = new FileInputStream(new File("/jay.txt"));
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
} finally {
    try { if (fdIn != null) fdIn.close(); } catch (IOException e) { log.error(e); }
}
try (FileInputStream inputStream = new FileInputStream(new File("jay.txt"))) {
    // use resources
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
}

6. Guard against runtime errors

Check collection size before accessing elements and avoid division by zero or null dereferences.

if (CollectionsUtil.isNotEmpty(list) && list.size() > 1) {
    String name = list.get(1).getName();
}

7. Batch remote or database calls

Avoid making remote or DB calls inside loops; retrieve data in bulk (e.g., 500 records per batch).

remoteBatchQuery(param);
for (int i = 0; i < n; i++) {
    remoteSingleQuery(param);
}

8. Consider concurrency for read‑modify‑write

Operations that read a record then update it are not atomic; under multithreading they can cause lost updates. Use atomic DB operations (e.g., delete‑if‑exists) to ensure consistency.

if (deleteAvailableTicketById(ticketId) == 1) {
    // add cash
} else {
    return "No available coupon";
}

Thread A adds cash

Thread B adds cash

Thread A deletes ticket flag

Thread B deletes ticket flag

9. Null‑check before accessing object properties

Always verify an object is not null before calling its methods to avoid NullPointerException.

if (object != null) {
    String name = object.getName();
}

10. Use appropriate thread pools instead of creating raw threads

Thread pools reduce creation overhead, improve response time, and enable resource reuse. Separate critical business workloads into isolated pools with suitable configurations.

Manage threads efficiently

Improve latency

Reuse resources

11. Run hand‑written SQL in the database and check the execution plan

Executing SQL manually helps catch syntax errors and allows you to use EXPLAIN to verify index usage.

explain select * from user where userid = 10086 or age = 18;

12. Handle third‑party API calls with retries, timeouts, and security

When invoking external services, configure connection timeouts, retry counts, and, for sensitive operations like payments, add signature verification and encryption.

Example: set connect‑time and retry attempts for an HTTP request.

13. Design idempotent interfaces

Idempotent APIs produce the same effect regardless of how many times they are called, preventing duplicate processing in scenarios like rapid user clicks.

Query operations

Unique indexes

Token mechanisms

Database delete

Optimistic / pessimistic locks

Distributed locks (Redis, Zookeeper)

State‑machine based idempotency

14. Ensure linear safety in high‑concurrency scenarios

Standard collections like HashMap are not thread‑safe; replace them with ConcurrentHashMap or other concurrent structures under heavy load.

HashMap, ArrayList, LinkedList, TreeMap – not thread‑safe Vector, Hashtable, ConcurrentHashMap – thread‑safe

15. Consider master‑slave replication lag

Writes go to the master while reads may hit a lagging replica; for critical data, force reads from the master or redesign to tolerate eventual consistency.

16. Cache consistency and protection against cache pitfalls

Cache usage speeds up reads but requires careful handling of consistency, cache penetration, cache avalanche, and cache breakdown.

Cache avalanche: massive expiration causing DB overload. Cache penetration: repeated DB hits for non‑existent keys. Cache breakdown: hot key expires, leading to a surge of DB requests.

Git repository: https://github.com/whx123/JavaHome

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.

JavaBackend DevelopmentSoftware Engineeringcoding habits
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

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.