Fundamentals 22 min read

Java Code Optimization Tips and Best Practices

This article presents a comprehensive collection of Java code optimization techniques, covering topics such as using final modifiers, object reuse, local variables, proper resource management, loop improvements, lazy loading, exception handling, collection sizing, and efficient map traversal to enhance performance and reduce memory usage.

Java Captain
Java Captain
Java Captain
Java Code Optimization Tips and Best Practices

Preface

Code optimization is an important topic; even seemingly insignificant changes can accumulate to a noticeable performance boost, much like a whale gaining weight by eating many tiny shrimp.

Goals of Code Optimization

1. Reduce the size of the code. 2. Improve the runtime efficiency of the code.

Optimization Details

1. Use the final modifier for classes and methods

Marking a class as final prevents it from being subclassed. Declaring a method as final allows the JVM to inline it, which can improve performance by up to 50%.

2. Reuse objects whenever possible

Especially for String objects, use StringBuilder or StringBuffer for concatenation to avoid creating many temporary objects that increase garbage‑collection overhead.

3. Prefer local variables

Method parameters and temporary variables are stored on the stack, which is faster than heap‑allocated static or instance variables and does not require extra garbage collection.

4. Close streams promptly

When working with database connections or I/O streams, always close them after use to release resources and avoid large system overhead.

5. Avoid repeated calculations of the same variable

Cache the result of expensive calls, e.g., replace repeated list.size() calls with a cached length:

for (int i = 0, length = list.size(); i < length; i++) {
    // ...
}

6. Apply lazy loading

Create objects only when they are needed. Example:

String str = "aaa";
if (i == 1) {
    list.add(str);
}

After refactoring, the object creation is moved inside the conditional block.

7. Use exceptions sparingly

Throwing an exception creates a new object and captures a stack trace, which is costly. Exceptions should be used for error handling, not for controlling program flow.

8. Place try…catch blocks at the outermost level when possible

Wrapping inner loops with try…catch can degrade performance and make the code harder to read.

9. Pre‑size collections when the expected size is known

For array‑based collections such as ArrayList, StringBuilder, HashMap, etc., specify an initial capacity to avoid repeated resizing and copying.

10. Use System.arraycopy() for bulk copying

When copying large arrays, System.arraycopy() is much faster than manual element‑by‑element copying.

11. Replace multiplication/division with bit‑shift operations when appropriate

for (int val = 0; val < 100000; val += 5) {
    a = val << 3; // val * 8
    b = val >> 1; // val / 2
}

Bit‑shifts are faster but should be documented for readability.

12. Avoid creating objects inside tight loops

for (int i = 1; i <= count; i++) {
    Object obj = new Object(); // creates many objects
}

Instead, reuse a single reference or move object creation outside the loop.

13. Prefer arrays over ArrayList when the size is fixed

Arrays have less overhead and better cache locality.

14. Prefer non‑synchronized collections unless thread safety is required

Use HashMap, ArrayList, StringBuilder instead of their synchronized counterparts ( Hashtable, Vector, StringBuffer) to avoid unnecessary locking.

15. Do not declare arrays as public static final

While the reference is constant, the array contents can still be modified, which may lead to security issues.

16. Use the Singleton pattern judiciously

Singletons can reduce loading time and resource usage but should only be applied when a single shared instance truly makes sense (resource control, instance control, data sharing).

17. Avoid overusing static variables

Static references prevent the garbage collector from reclaiming the objects they point to, potentially causing memory leaks.

18. Explicitly invalidate unused HTTP sessions

Calling HttpSession.invalidate() frees session resources and prevents unnecessary serialization in clustered environments.

19. Use a classic for loop for RandomAccess collections

if (list instanceof RandomAccess) {
    for (int i = 0; i < list.size(); i++) {
        // fast random access
    }
} else {
    for (Iterator<?> it = list.iterator(); it.hasNext(); ) {
        it.next();
    }
}

20. Prefer synchronized blocks over synchronized methods

Synchronize only the critical section to avoid locking code that does not need protection.

21. Declare constants as static final and use uppercase names

This allows the compiler to place them in the constant pool and makes them easy to identify.

22. Remove unused variables and imports

Eliminate warnings such as "The value of the local variable i is not used" and "The import java.util is never used".

23. Minimize the use of reflection at runtime

Reflection is powerful but incurs a performance penalty; cache reflective objects when they must be used.

24. Use connection pools and thread pools

Pooling reuses expensive resources like database connections and threads, reducing creation overhead.

25. Use buffered I/O streams

Classes such as BufferedReader, BufferedWriter, BufferedInputStream, and BufferedOutputStream greatly improve I/O efficiency.

26. Choose ArrayList for random access and LinkedList for frequent insertions/removals

Understanding their internal structures helps select the right implementation.

27. Keep the number of method parameters reasonable

Too many parameters (more than 3‑4) violate object‑oriented principles and increase the chance of errors; consider encapsulating parameters in a DTO.

28. Write constant strings first in equals checks

if ("123".equals(str)) {
    // avoid NullPointerException
}

29. Prefer i == 1 over 1 == i in Java for readability

Both are equivalent, but the former is more idiomatic in Java.

30. Do not use toString() on arrays

Calling array.toString() prints the object’s hash code (e.g., [I@18a992f) rather than its contents. Use Arrays.toString(array) instead.

31. Avoid unsafe down‑casting of primitive types

Casting a large long to int truncates the high bits and yields unexpected values.

32. Remove unused elements from shared collections

Failing to clean up unused entries can cause memory leaks in long‑lived collections.

33. Convert primitive types to String efficiently

Use primitive.toString() (fastest), then String.valueOf(primitive), and avoid primitive + "" (slowest).

34. Iterate over Map efficiently

Set<Map.Entry<String, String>> entrySet = map.entrySet();
Iterator<Map.Entry<String, String>> iter = entrySet.iterator();
while (iter.hasNext()) {
    Map.Entry<String, String> entry = iter.next();
    System.out.println(entry.getKey() + "\t" + entry.getValue());
}

For only keys, use map.keySet().

35. Close resources separately to avoid loss on exception

try { xxx.close(); } catch (Exception e) { /* handle */ }
try { yyy.close(); } catch (Exception e) { /* handle */ }

This guarantees that each resource is closed even if the previous close() throws.

Conclusion

Applying these 35 practical tips can significantly improve Java application performance, reduce memory consumption, and prevent common pitfalls such as resource leaks and unnecessary object creation.

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.

JavaperformanceefficiencyprogrammingCode Optimization
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

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.