30 Practical Java Code Optimization Tips to Supercharge Your Applications
This article presents a comprehensive collection of thirty Java performance‑tuning techniques—from using String.format and buffered I/O streams to avoiding large transactions, leveraging enums, and handling thread‑local resources—each illustrated with clear code examples and best‑practice recommendations for modern backend development.
Introduction
Hello everyone, I'm Su San, back with another Java performance‑tuning guide. After two popular posts on SQL and API optimization, we now dive into thirty practical Java code‑optimization tips.
1. Use String.format for String Concatenation
Instead of concatenating many parameters with the + operator, build the URL with String.format for better readability.
String requestUrl = "http://susan.sc.cn?userName=%s&age=%s&address=%s&sex=%s&roledId=%s";
String url = String.format(requestUrl, userName, age, address, sex, roledId);Do not use String.format inside tight loops because it is slower than + or StringBuilder .
2. Create Buffered I/O Streams
Wrap raw FileInputStream and FileOutputStream with BufferedInputStream and BufferedOutputStream and use a byte buffer to reduce the number of read/write operations.
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.flush();3. Reduce Loop Iterations
Replace nested loops with a map lookup to avoid O(N²) processing.
Map<Long, List<Role>> roleMap = roleList.stream()
.collect(Collectors.groupingBy(Role::getId));
for (User user : userList) {
List<Role> roles = roleMap.get(user.getRoleId());
if (CollectionUtils.isNotEmpty(roles)) {
user.setRoleName(roles.get(0).getName());
}
}4. Close Resources Promptly
Always close ResultSet, PreparedStatement, and Connection in a finally block or use try‑with‑resources.
try {
// use resources
} finally {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (connection != null) connection.close();
}5. Use Connection Pools
Replace raw JDBC connections with a pool such as Druid, C3P0, or Apache DBCP to reuse connections and limit the maximum number of active connections.
6. Cache Reflection Results
When using reflection for dynamic instantiation, cache the class instances or method look‑ups to avoid repeated costly reflective calls.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PayCode { String value(); String name(); }
@Service
public class PayService2 implements ApplicationListener<ContextRefreshedEvent> {
private static Map<String, IPay> payMap = null;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Map<String, Object> beans = event.getApplicationContext()
.getBeansWithAnnotation(PayCode.class);
if (beans != null) {
payMap = new HashMap<>();
beans.forEach((k, v) -> {
String bizType = v.getClass()
.getAnnotation(PayCode.class).value();
payMap.put(bizType, (IPay) v);
});
}
}
public void pay(String code) { payMap.get(code).pay(); }
}7. Use Thread Pools for Parallel Remote Calls
Replace sequential remote‑service calls with CompletableFuture (or Callable before Java 8) to execute them concurrently.
CompletableFuture<User> userFuture = CompletableFuture.supplyAsync(() -> getRemoteUser(id), executor);
CompletableFuture<Bonus> bonusFuture = CompletableFuture.supplyAsync(() -> getRemoteBonus(id), executor);
CompletableFuture<Growth> growthFuture = CompletableFuture.supplyAsync(() -> getRemoteGrowth(id), executor);
CompletableFuture.allOf(userFuture, bonusFuture, growthFuture).join();8. Lazy Loading
Use lazy initialization (e.g., the lazy singleton pattern) to defer costly object creation until it is actually needed.
public class SimpleSingleton2 {
private static SimpleSingleton2 INSTANCE;
private SimpleSingleton2() {}
public static SimpleSingleton2 getInstance() {
if (INSTANCE == null) {
INSTANCE = new SimpleSingleton2();
}
return INSTANCE;
}
}9. Pre‑size Collections
When you know the expected size, construct collections with an initial capacity to avoid repeated resizing.
List<Integer> list = new ArrayList<>(100000);10. Avoid Large Transactions
Keep transactions short, move read‑only queries outside, avoid remote calls inside a transaction, and process data in batches.
11. Replace Long if…else Chains
Apply the Strategy pattern combined with a simple factory to map a code to a concrete implementation, eliminating massive if…else blocks.
public interface IPay { void pay(); }
@Service
public class AliaPay implements IPay {
@PostConstruct
public void init() { PayStrategyFactory.register("alia", this); }
public void pay() { System.out.println("===Alipay==="); }
}
// similar for WeixinPay, JingDongPay
public class PayStrategyFactory {
private static final Map<String, IPay> REGISTERS = new HashMap<>();
public static void register(String code, IPay impl) { REGISTERS.put(code, impl); }
public static IPay get(String code) { return REGISTERS.get(code); }
}
@Service
public class PayService3 {
public void toPay(String code) { PayStrategyFactory.get(code).pay(); }
}12. Prevent Infinite Loops
When using while(true), ensure the break condition is reliable; also guard recursive methods with a maximum depth to avoid stack overflow.
13. Beware of BigDecimal Precision
Never use the new BigDecimal(double) constructor; instead use BigDecimal.valueOf(double) or the String constructor to keep exact decimal values.
BigDecimal a = BigDecimal.valueOf(0.02);
BigDecimal b = BigDecimal.valueOf(0.03);
System.out.println(b.subtract(a)); // 0.0114. Use Enums for Fixed Status Values
Replace scattered integer constants with a type‑safe enum that holds both code and description.
public enum OrderStatus {
CREATE(1, "Created"),
PAY(2, "Paid"),
DONE(3, "Completed"),
CANCEL(4, "Cancelled");
private final int code;
private final String message;
OrderStatus(int code, String message) { this.code = code; this.message = message; }
public int getCode() { return code; }
public String getMessage() { return message; }
public static OrderStatus fromCode(int code) {
return Arrays.stream(values())
.filter(s -> s.code == code)
.findFirst()
.orElse(null);
}
}15. Define Static Final Constants
Replace magic numbers and strings with private static final fields for readability and maintainability.
16. Avoid Large Transactions (Repeated)
Same advice as section 10 – keep transactions small, move selects out, avoid remote calls, and consider async processing.
17. Eliminate Overly Long if…else
Use design patterns (Strategy, Factory, Enum) to keep code clean and extensible.
18. Prevent Dead Loops in foreach
Do not remove elements from a collection while iterating with foreach; use an explicit iterator or a traditional for loop.
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
if ("c".equals(s)) {
it.remove();
}
}19. Avoid Unnecessary Logging
Guard expensive log statements with if (log.isDebugEnabled()) so they are only executed when the appropriate log level is active.
20. Write Constants First in equals()
When comparing strings, place the constant on the left side to avoid NullPointerException.
if ("SuSan".equals(user.getName())) { ... }21. Meaningful Naming
Use clear, English, camel‑case names for variables, methods, and classes; avoid single letters, Chinese pinyin, or inconsistent styles.
22. SimpleDateFormat Is Not Thread‑Safe
Never share a static SimpleDateFormat instance; either create a new instance per use, store it in a ThreadLocal, or switch to Java 8's DateTimeFormatter.
23. Prefer Custom ThreadPoolExecutor Over Executors
Define explicit core size, max size, keep‑alive time, queue capacity, and rejection policy to avoid unbounded queues or thread explosion.
ExecutorService pool = new ThreadPoolExecutor(
8, 10, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(500),
new ThreadPoolExecutor.CallerRunsPolicy()
);24. Arrays.asList Returns Fixed‑Size List
The list returned by Arrays.asList cannot be resized; use new ArrayList<>(Arrays.asList(...)) if you need to add or remove elements.
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.add("d");Conclusion
If you found these tips useful, please like, follow, or star the GitHub repository https://github.com/dvsusan/susanSayJava for more Java performance articles.
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.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
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.
