9 Essential Java Code Optimizations to Eliminate Bad Practices

This article presents nine practical Java code‑optimization techniques—including string formatting, loop refactoring, resource management, buffered I/O, multithreading, enums, exception handling, and third‑party libraries—each illustrated with before‑and‑after code samples and clear explanations of why the improved version is more readable, efficient, and maintainable.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
9 Essential Java Code Optimizations to Eliminate Bad Practices

In Java projects, common problems such as chaotic string concatenation, nested loops, unreleased resources, redundant if‑else chains, and duplicated exception handling reduce readability, maintainability, and performance. The following nine optimizations address these issues using Spring Boot 3.5.0 as the runtime environment.

1. Use String.format() or .formatted() for string construction

Concatenating many values with the + operator quickly becomes unreadable, especially for URLs or log messages.

Before:

String url = "http://localhost:8080?name=" + name +
            "&age=" + age +
            "&address=" + address +
            "&sex=" + sex ;

Improved version with StringBuilder :

StringBuilder sb = new StringBuilder("http://localhost:8080?");
sb.append("name=").append(name)
  .append("&age=").append(age)
  .append("&address=").append(address)
  .append("&sex=").append(sex);
String url = sb.toString();

More concise version with String.format :

String requestUrl = "http://localhost:8080?name=%s&age=%s&address=%s&sex=%s";
String url = String.format(requestUrl, name, age, address, sex);

For Java 15+, the same can be written as "...".formatted(name, age, address, sex). Note: avoid String.format() inside large loops because it is slower than StringBuilder .

2. Reduce nested loops

Deeply nested loops increase the total number of operations dramatically (e.g., two lists of 10,000 elements lead to 100 million comparisons).

Before:

for (Order order : orders) {
    for (Product product : products) {
        if (order.getProductId().equals(product.getId())) {
            order.setProductName(product.getName());
        }
    }
}

After: build a map of products keyed by ID, then look up directly.

Map<Long, Product> productMap = products.stream()
        .collect(Collectors.toMap(Product::getId, product -> product));
for (Order order : orders) {
    Product product = productMap.get(order.getProductId());
    if (product != null) {
        order.setProductName(product.getName());
    }
}

3. Properly close resources with try‑with‑resources

Leaving JDBC connections, streams, or result sets open can cause resource leaks and eventual application crashes.

Before:

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "root", "root");
PreparedStatement pstmt = conn.prepareStatement("select * from t_user");
ResultSet rs = pstmt.executeQuery();
// resources never closed

Legacy manual close:

Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
    conn = DriverManager.getConnection(...);
    pstmt = conn.prepareStatement(...);
    rs = pstmt.executeQuery();
} catch (Exception e) {
    // ...
} finally {
    try { if (rs != null) rs.close(); } catch (Exception e) {}
    try { if (pstmt != null) pstmt.close(); } catch (Exception e) {}
    try { if (conn != null) conn.close(); } catch (Exception e) {}
}

Modern try‑with‑resources:

try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "root", "root");
     PreparedStatement pstmt = conn.prepareStatement("select * from t_user");
     ResultSet rs = pstmt.executeQuery()) {
    while (rs.next()) {
        System.out.println(rs.getString("name"));
    }
} catch (Exception e) {
    e.printStackTrace();
}

4. Use buffered I/O streams

Reading or writing one byte at a time causes many disk operations and slows down large‑file processing.

Before:

FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
int data;
while ((data = fis.read()) != -1) {
    fos.write(data);
}
fos.flush();

After:

try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
     BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile))) {
    byte[] buffer = new byte[4096];
    int len;
    while ((len = bis.read(buffer)) != -1) {
        bos.write(buffer, 0, len);
    }
}

Benefits: block‑level reads/writes, fewer disk accesses, better performance for large files, and automatic resource closing via try‑with‑resources.

5. Parallelize independent tasks with CompletableFuture

Sequentially invoking multiple services can lead to long total latency.

Before:

public void fetchData() {
    String user = getUserData();
    String orders = getOrderData();
    String payments = getPaymentData();
    // ...
}

After:

public void fetchData() {
    CompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() -> getUserData());
    CompletableFuture<String> orderFuture = CompletableFuture.supplyAsync(() -> getOrderData());
    CompletableFuture<String> paymentFuture = CompletableFuture.supplyAsync(() -> getPaymentData());
    CompletableFuture.allOf(userFuture, orderFuture, paymentFuture).join();
    // ...
}

Result: independent tasks run concurrently, reducing overall response time, especially for I/O‑bound operations.

6. Represent fixed states with enums

Using raw integers or strings for status values makes code hard to read and error‑prone.

Before:

public class Task {
    public static final int PENDING = 1;
    public static final int IN_PROGRESS = 2;
    public static final int COMPLETED = 3;
    private int status;
}

After:

public enum TaskStatus {
    PENDING,
    IN_PROGRESS,
    COMPLETED
}

7. Eliminate long if‑else chains with a map lookup

Long conditional chains are difficult to maintain and extend.

Before:

public void sendNotification(String type) {
    if ("EMAIL".equals(type)) {
        sendEmail();
    } else if ("SMS".equals(type)) {
        sendSMS();
    } else if ("PUSH".equals(type)) {
        sendPushNotification();
    } else {
        System.out.println("Unknown notification type");
    }
}

After:

Map<String, Runnable> notificationMap = new HashMap<>();
notificationMap.put("EMAIL", this::sendEmail);
notificationMap.put("SMS", this::sendSMS);
notificationMap.put("PUSH", this::sendPushNotification);

public void sendNotification(String type) {
    Runnable action = notificationMap.get(type);
    if (action != null) {
        action.run();
    } else {
        System.out.println("Unknown notification type");
    }
}

Benefits: clearer code, easier extension, reduced conditional complexity.

8. Centralize exception handling with @RestControllerAdvice

Repeating try‑catch blocks in each controller pollutes the code.

Before:

@GetMapping("/divide")
public int divide(int a, int b) {
    try {
        return a / b;
    } catch (ArithmeticException e) {
        return 0;
    }
}

After:

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ArithmeticException.class)
    public ResponseEntity<Object> handleArithmeticException(ArithmeticException ex) {
        return ResponseEntity.ok(ex.getMessage());
    }
    @ExceptionHandler(Exception.class)
    public ResponseEntity<R> handleGeneralException(Exception ex) {
        return ResponseEntity.ok(R.error(ex.getMessage()));
    }
}

// Controller now stays simple
@GetMapping("/divide")
public int divide(int a, int b) {
    return a / b;
}

Advantages: removes duplicated try‑catch, keeps controllers clean, provides consistent error responses, and eases maintenance in large applications.

9. Leverage third‑party libraries to avoid reinventing utilities

Java’s ecosystem offers mature libraries that simplify common tasks.

Guava

Apache Commons

Jackson

Example: replace a manual string‑blank check with Apache Commons’ StringUtils.isBlank:

import org.apache.commons.lang3.StringUtils;
boolean result = StringUtils.isBlank(str);

Using well‑tested libraries reduces boilerplate, improves readability, and minimizes bugs.

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.

JavaperformanceException HandlingCode Optimizationbest practicesSpring Bootmultithreading
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

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.