30 Essential Java Code Optimization Tips to Boost Performance
This article explains why code optimization matters—preventing hidden bugs and reducing downtime—then presents a comprehensive list of practical Java techniques, from using final modifiers and reusing objects to efficient looping, proper resource handling, and avoiding common pitfalls, all illustrated with concrete code examples.
Code optimization is crucial for preventing hard‑to‑detect runtime errors and reducing the time a service is unavailable during deployments. By addressing issues early in the source code, developers can dramatically lower maintenance effort and improve overall system stability.
The main goals of optimization are to shrink the compiled size and to increase execution efficiency.
Code Optimization Details
1. Mark classes and methods as final – final classes cannot be subclassed and final methods are candidates for inlining, which can raise performance by up to 50%.
2. Reuse objects whenever possible – for example, use StringBuilder instead of concatenating String objects, reducing garbage‑collection overhead.
3. Prefer local variables over fields – locals are stored on the stack and are faster to allocate and discard than heap‑based static or instance fields.
4. Close streams promptly – always close database connections, I/O streams, etc., after use to free resources and avoid memory‑leak risks.
5. Avoid repeated calculations inside loops – cache results such as list.size() before the loop:
for (int i = 0, length = list.size(); i < length; i++) {
// ...
}6. Apply lazy loading – create objects only when they are needed:
String str = "aaa";
if (i == 1) {
list.add(str);
}Rewritten as:
if (i == 1) {
String str = "aaa";
list.add(str);
}7. Use exceptions sparingly – throwing an exception creates a new Throwable and captures a stack trace, which is expensive; reserve exceptions for genuine error handling.
8. Place try…catch blocks outside loops – avoid wrapping each iteration in a catch block; instead, catch once around the whole loop.
9. Pre‑size collections that implement array‑backed structures – for ArrayList, HashMap, StringBuilder, etc., specify an initial capacity when the expected size is known to avoid costly resizing.
10. Use System.arraycopy() for bulk copying – this native method is far faster than manual element‑by‑element copying.
11. Replace multiplication/division with bit shifts when appropriate – e.g., a = val << 3 instead of a = val * 8, and b = val >> 1 instead of b = val / 2. Add comments to preserve readability.
12. Avoid creating objects inside loops – create the object once outside the loop or reuse a single reference:
Object obj = null;
for (int i = 0; i <= count; i++) {
obj = new Object();
}13. Prefer arrays over ArrayList when the size is fixed – arrays have lower overhead and better cache locality.
14. Use non‑synchronised collections (e.g., HashMap , ArrayList , StringBuilder ) unless thread safety is required – synchronized alternatives like Hashtable or Vector incur extra locking costs.
15. Do not declare public arrays as static final – the reference is immutable but the array contents can still be modified, exposing internal state.
16. Apply the Singleton pattern judiciously – useful for resource control, instance limiting, and shared data, but only when a single instance truly makes sense.
17. Minimise static variables – static references prevent garbage collection of the objects they point to, potentially causing memory leaks.
18. Invalidate unused HTTP sessions – call HttpSession.invalidate() to free session data and avoid serialization overhead in large clusters.
19. For RandomAccess lists (e.g., ArrayList ), use a classic for loop instead of foreach – this yields better performance for random access.
20. Prefer synchronized blocks over synchronized methods – limit the synchronized region to the critical section to reduce contention.
21. Declare constants as static final and name them in uppercase – enables compile‑time inlining and clear distinction from variables.
22. Remove unused objects and imports – eliminate dead code such as “the value of the local variable i is not used”.
23. Avoid reflection in performance‑critical paths – reflective calls (especially Method.invoke) are slow; cache reflective objects if they must be used.
24. Use connection pools and thread pools – reuse database connections and threads to avoid the overhead of creation and destruction.
25. Use buffered I/O streams – BufferedReader, BufferedWriter, etc., dramatically improve I/O throughput.
26. Choose ArrayList for frequent sequential access and LinkedList for many insertions/removals – understand the trade‑offs of each implementation.
27. Limit the number of parameters in public methods – too many parameters break object‑oriented design and increase error probability; wrap related data in a DTO.
28. Write constant strings first in equals checks – "123".equals(str) prevents possible NullPointerException.
29. Prefer if (1 == i) over if (i == 1) in C/C++ style languages to avoid accidental assignment .
30. Do not call toString() on arrays – it yields an unreadable hash code; use Arrays.toString() or iterate manually.
31. Avoid unsafe down‑casting of primitive types – casting a large long to int truncates high‑order bits, leading to unexpected values.
32. Remove unused entries from shared collections – otherwise they grow indefinitely and cause memory leaks.
33. Convert primitives to String efficiently – Integer.toString() is fastest, followed by String.valueOf(); concatenation with + "" is slowest.
34. Iterate Map efficiently – use entrySet().iterator() for key‑value pairs, or keySet() if only keys are needed.
35. Close resources in separate try blocks – ensures each close() executes even if a previous close throws an exception.
36. Remove ThreadLocal values after use – thread pools reuse threads, so lingering ThreadLocal data can leak between tasks.
37. Replace magic numbers with named constants – improves readability and maintainability.
38. Use uppercase L for long literals – avoids confusion with the digit 1.
39. Annotate overridden methods with @Override – catches signature mismatches at compile time and clarifies inheritance.
40. Use Objects.equals(a, b) (Java 7+) for null‑safe comparisons – prevents NullPointerException.
41. Avoid string concatenation with + inside loops – use a single StringBuilder and append repeatedly.
42. Do not catch runtime exceptions that extend RuntimeException – they can usually be prevented by defensive checks (e.g., avoid ArithmeticException, NullPointerException, IndexOutOfBoundsException, etc.).
43. Prefer ThreadLocalRandom over shared Random in multithreaded code – eliminates contention on the internal seed.
44. Make constructors of utility, singleton, and factory classes private – prevents accidental instantiation.
http://www.cnblogs.com/xrq730/p/4868465.html
http://www.cnblogs.com/xrq730/p/4851530.html
http://www.cnblogs.com/xrq730/p/4862111.html
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.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
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.
