30 Essential Java Code Optimization Tips for Faster Applications
This article presents a comprehensive collection of Java performance best practices, covering topics such as using final modifiers, object reuse, local variables, stream handling, avoiding repeated calculations, lazy loading, exception handling, collection sizing, bit‑shifts, loop optimizations, reflection avoidance, resource pooling, buffered I/O, and proper map traversal, all aimed at reducing code size and boosting runtime efficiency.
Code optimization is an important topic. Some may think it is useless, but like a whale eating a tiny shrimp, many small optimizations accumulate to significantly improve performance.
If a project aims for quick bug‑free release, you can focus on major issues; when you have enough time for development and maintenance, every detail matters, as small optimizations together can noticeably enhance runtime efficiency.
Goals of Code Optimization
Reduce code size.
Improve runtime efficiency.
Code Optimization Details
1. Prefer final on classes and methods
Classes marked final cannot be subclassed. Core APIs like java.lang.String are final. Declaring a class or method final allows the compiler to inline calls, which can raise performance by about 50%.
2. Reuse objects
Especially for String, use StringBuilder / StringBuffer instead of concatenation to avoid creating many temporary objects that increase GC overhead.
3. Use local variables whenever possible
Method parameters and temporary variables are stored on the stack, which is faster than heap‑allocated static or instance fields.
4. Close streams promptly
When using database connections or I/O streams, close them as soon as they are no longer needed to release resources and avoid heavy system overhead.
5. Avoid repeated calculations
Method calls have overhead even for a single statement. Example: for (int i = 0; i < list.size(); i++) { ... } Replace with:
for (int i = 0, length = list.size(); i < length; i++) { ... }6. Lazy‑load objects
Instantiate objects only when needed. Example:
String str = "aaa";
if (i == 1) {
list.add(str);
}Change to:
if (i == 1) {
String str = "aaa";
list.add(str);
}7. Use exceptions sparingly
Throwing an exception creates a new Throwable and fills the stack trace, which is costly. Exceptions should be for error handling, not program flow control.
8. Keep try‑catch outside loops
Place try‑catch blocks at the outermost level unless unavoidable; otherwise they add unnecessary overhead.
9. Pre‑size collections when possible
Specify initial capacity for ArrayList, StringBuilder, HashMap, etc., to avoid repeated array resizing and copying.
10. Use System.arraycopy for bulk copies
When copying large amounts of data, System.arraycopy is much faster than element‑by‑element copying.
11. Use bit‑shift for multiplication/division by powers of two
Example:
for (val = 0; val < 100000; val += 5) {
a = val * 8;
b = val / 2;
}Replace with:
for (val = 0; val < 100000; val += 5) {
a = val << 3;
b = val >> 1;
}Note: add comments if readability is a concern.
12. Avoid creating objects inside loops
Creating a new object each iteration consumes memory. Reuse a single reference when possible.
13. Prefer arrays over ArrayList when size is known
Use plain arrays for fixed‑size data; resort to ArrayList only when the size is uncertain.
14. Prefer non‑synchronized collections unless thread safety is required
Use HashMap, ArrayList, StringBuilder instead of Hashtable, Vector, StringBuffer which incur synchronization overhead.
15. Do not declare arrays as public static final
Static final only fixes the reference, not the contents; exposing the array publicly is a security risk.
16. Use singleton pattern wisely
Singletons reduce loading cost and improve efficiency when resource sharing is needed, but should be applied only where appropriate.
17. Avoid unnecessary static variables
Static references prevent garbage collection of the referenced objects, leading to memory leaks.
18. Explicitly invalidate unused sessions
Call HttpSession.invalidate() to free session resources and avoid memory pressure.
19. Iterate RandomAccess collections with classic for loops
For lists implementing RandomAccess, a simple index loop is faster than a foreach loop.
20. Prefer synchronized blocks over synchronized methods
Synchronize only the critical section to reduce lock contention.
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 objects and imports
Eliminate dead code and unnecessary imports to keep the codebase clean.
23. Minimize use of reflection at runtime
Reflection incurs performance penalties; instantiate reflective classes at startup if needed.
24. Use connection pools and thread pools
Reuse database connections and threads to avoid costly creation and destruction.
25. Use buffered I/O streams
BufferedReader, BufferedWriter, BufferedInputStream, BufferedOutputStream greatly improve I/O efficiency.
26. Choose ArrayList for random access, LinkedList for frequent insert/delete
Understanding their internal mechanisms helps select the right structure.
27. Limit the number of parameters in public methods
Too many parameters violate object‑oriented principles and increase error risk; consider encapsulating parameters in a DTO.
28. Put constant string first in equals comparisons
Writing "123".equals(str) avoids NullPointerException.
29. Prefer i == 1 over 1 == i for readability
Both are equivalent, but the former reads more naturally.
30. Do not use toString() on arrays
array.toString()prints a hash code; use Arrays.toString() to display contents.
31. Beware of narrowing primitive casts
Casting long to int truncates high‑order bits, leading to unexpected values.
32. Remove unused data from shared collections
Otherwise memory leaks may occur as the collection grows indefinitely.
33. Convert primitives to String efficiently
toString()is fastest, followed by String.valueOf(), then concatenation with "".
34. Iterate maps efficiently
Iterate over entrySet() with an iterator for best performance; use keySet() if only keys are needed.
35. Close resources separately
Separate try‑catch blocks for each close() operation to guarantee all resources are released even if one close throws an exception.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
