45 Essential Java Coding Practices to Rescue Legacy Code

This article compiles 45 practical Java coding tips—from naming conventions and formatting to exception handling, thread safety, design patterns, and refactoring strategies—aimed at improving readability, maintainability, and performance of existing codebases while preventing common pitfalls.

Sanyou's Java Diary
Sanyou's Java Diary
Sanyou's Java Diary
45 Essential Java Coding Practices to Rescue Legacy Code

1. Naming Conventions

Use clear, descriptive names for classes, methods, variables, and parameters. Replace ambiguous names like int i = 0; with meaningful ones such as int count = 0;, and prefer readable English identifiers (e.g., private String idCardNo;private String idCardNo;).

2. Code Formatting

Adopt consistent spacing, brace alignment, and line length. Modern IDEs can auto‑format code to improve visual comfort.

3. Write Good Comments

Comments should explain intent, describe parameters and return values, warn about constraints, and use // TODO for unfinished work. They supplement code when the logic cannot be expressed clearly.

4. Extract Try‑Catch Logic

Move the core logic inside a try‑catch block to a separate method to keep the main flow readable.

5. Keep Methods Short

A method should do one thing; long methods become hard to understand. Refactor large methods using patterns like Strategy.

6. Remove Duplicate Code

Extract repeated logic into utility classes or common super‑classes to improve extensibility.

7. Use Early Returns

Replace deep nested if statements with early return statements to flatten control flow.

if (!condition1) { return; }
if (!condition2) { return; }
// ...
System.out.println("Result");

8. Simplify Complex Conditions

Break complicated boolean expressions into well‑named variables before the final if check.

boolean isBlankOrSpecial = StringUtils.isBlank(name) || "Special".equals(name);
boolean ageOk = age != null && age > 10;
boolean isHan = "汉".equals(national);
if (isBlankOrSpecial && ageOk && isHan) { /* logic */ }

9. Elegant Parameter Validation

Leverage Bean Validation annotations such as @NotBlank and @NotNull on DTOs and add @Valid on controller methods.

@Data
public class AddPersonRequest {
    @NotBlank(message = "Name cannot be empty")
    private String name;
    @NotBlank(message = "ID Card cannot be empty")
    private String idCardNo;
}

10. Unified Return Structure

Standardize API responses with a common wrapper containing code, message, and data fields.

{
  "code": 0,
  "message": "Success",
  "data": "..."
}

11. Global Exception Handling

Use Spring’s @ControllerAdvice to avoid repetitive try‑catch blocks across controllers.

12. Avoid Passing Null

Prefer @NonNull and @Nullable annotations to make nullability explicit.

public void updatePerson(@Nullable Person person) {
    if (person == null) { return; }
    personService.updateById(person);
}

13. Avoid Returning Null

Return Optional instead of null for potentially absent values.

public Optional<Person> getPersonById(Long id) {
    return Optional.ofNullable(personService.selectById(id));
}

14. Logging Standards

Make logs searchable with clear keywords.

Log stack traces for errors.

Use appropriate log levels (error, info).

Avoid logging huge payloads like Base64 images.

15. Consistent Library Usage

Choose a single JSON library (e.g., Jackson) and avoid mixing multiple libraries.

16. Prefer Utility Classes

Use collection utilities (e.g., CollectionUtils.isEmpty()) instead of manual checks.

17. Extract Magic Numbers

Replace literal constants with named constants for readability.

private static final String GUANG_DONG = "广东省";
if (GUANG_DONG.equals(province)) { System.out.println("靓仔~~"); }

18. Release Resources in finally

Always release locks or I/O resources inside a finally block.

19. Use Thread Pools

Replace manual thread creation with ExecutorService to reuse threads and control concurrency.

20. Name Threads

Assign meaningful names to threads to simplify debugging.

21. Use volatile for Visibility

Mark shared flags with volatile to guarantee visibility across threads.

22. Reduce Lock Scope

Only lock the critical section; keep non‑critical code outside the lock.

23. Define Enums for Types

Use enums instead of magic numbers to represent distinct categories.

24. Set Timeouts on Remote Calls

Configure timeouts for RPC or HTTP calls to avoid indefinite blocking.

25. Pre‑size Collections

Specify initial capacity for ArrayList and HashMap to reduce resizing overhead.

26. Avoid BeanUtils for Copying

Prefer compile‑time mappers like MapStruct over reflection‑based BeanUtils for better performance.

27. Use StringBuilder for Concatenation

When building strings in loops, use a single StringBuilder instead of the + operator.

StringBuilder sb = new StringBuilder();
String result = sb.append("123").append("456").append("789").toString();

28. Specify Rollback Exceptions

Annotate @Transactional with rollbackFor to include checked exceptions.

29. Beware of Self‑Invocation

Calling a proxied method from within the same class bypasses AOP; inject the proxy instead.

30. Select Required Fields

Query only needed columns to reduce network traffic and enable index‑only scans.

Wrappers.query().select("name");

31. Avoid DB Calls Inside Loops

Batch fetch data and map results instead of issuing a query per iteration.

32. Prefer Aggregation Over Inheritance

Use composition or aggregation to reduce coupling and improve flexibility.

public class OrderService {
    private UserService userService = new UserService(); // composition
}

33. Apply Design Patterns Wisely

Introduce patterns like Strategy when they solve a real problem; avoid over‑engineering.

public interface MessageNotifier { boolean support(int type); void notify(User u, String c); }

34. Interface‑Based Programming

Program to abstractions (interfaces) rather than concrete implementations for easier swapping.

35. Regular Refactoring

Continuously improve legacy code as business requirements evolve.

36. Null‑Check Discipline

Guard against NPEs by explicit null checks or using Optional.

37. Override toString in POJOs

Provide meaningful toString() implementations for debugging.

38. Use Constants for Magic Values

Replace hard‑coded literals with well‑named constants.

39. Thread‑Safe Collections

Choose concurrent collections (e.g., CopyOnWriteArrayList) when multiple threads access shared data.

40. Double‑Check Locking for Tokens

When caching tokens, use double‑check to prevent race conditions.

41. Reduce Lock Contention

Minimize the code inside synchronized blocks to improve throughput.

42. Avoid Unnecessary Asynchrony

Only use async execution when transaction integrity and CPU load are acceptable.

43. Use Enums for Fixed Types

Define enums for fixed categories such as attachment types.

44. Install Code Quality Plugins

Use tools like Alibaba Java Coding Guidelines plugin to enforce standards.

45. Communicate with Team

Discuss design decisions and seek peer reviews to avoid isolated mistakes.

References

Clean Code

Alibaba Java Development Manual

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.

JavaSoftware Engineeringbest practicescoding standardsrefactoring
Sanyou's Java Diary
Written by

Sanyou's Java Diary

Passionate about technology, though not great at solving problems; eager to share, never tire of learning!

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.