Boost Your Java Backend: Practical Coding Habits and Best Practices

This article shares a collection of practical Java backend coding habits—from using @ConfigurationProperties and @RequiredArgsConstructor, to modularizing code, handling exceptions, minimizing database queries, managing thread pools, naming caches, applying design patterns, and leveraging asynchronous tasks—to improve code quality and performance.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
Boost Your Java Backend: Practical Coding Habits and Best Practices

The author shares a set of practical coding habits for Java backend development.

Define Configuration File Information

Store variables in YAML files and use @ConfigurationProperties instead of @Value.

@Data
// specify prefix
@ConfigurationProperties(prefix = "developer")
@Component
public class DeveloperProperty {
    private String name;
    private String website;
    private String qq;
    private String phoneNumber;
}

Inject the bean where needed:

@RestController
@RequiredArgsConstructor
public class PropertyController {
    private final DeveloperProperty developerProperty;

    @GetMapping("/property")
    public Object index() {
        return developerProperty.getName();
    }
}

Use @RequiredArgsConstructor Instead of @Autowired

Constructor injection is the recommended way to inject beans.

Code Modularization

Keep each method under 50 lines, split logic into small, reusable units.

Throw Exceptions Instead of Returning Errors

Prefer throwing exceptions over returning error codes.

Bad example
Bad example
Good example
Good example

Reduce Unnecessary DB Queries

Avoid extra queries; delete only services that are offline or not yet launched.

Bad example
Bad example
Good example
Good example

Avoid Returning null

Bad example
Bad example
Good example
Good example

Prevent unnecessary NullPointerExceptions when calling methods elsewhere.

if else

Limit the number of if else if branches; consider the Strategy pattern.

Reduce Controller Business Logic

Move business logic to the service layer for better maintainability and readability.

Bad example
Bad example
Good example
Good example

Leverage IDE (IntelliJ IDEA)

IDE can suggest improvements, such as replacing anonymous classes with lambda expressions.

IDE suggestion
IDE suggestion

Read Source Code

Study high‑star open‑source projects on GitHub to learn design ideas and advanced APIs.

Design Patterns

Apply the 23 common design patterns to write clean, maintainable code.

Embrace New Knowledge

Junior developers should explore topics beyond daily CRUD, practice demos of more challenging concepts.

Fundamental Issues

Map traversal examples:

HashMap<String, String> map = new HashMap<>();
map.put("name", "du");
for (String key : map.keySet()) {
    String value = map.get(key);
}

map.forEach((k, v) -> {
    // ...
});

// Recommended
for (Map.Entry<String, String> entry : map.entrySet()) {
    // ...
}

Optional null‑check example:

public List<CatalogueTreeNode> getChild(String pid) {
    if (V.isEmpty(pid)) {
        pid = BasicDic.TEMPORARY_DIRECTORY_ROOT;
    }
    CatalogueTreeNode node = treeNodeMap.get(pid);
    return Optional.ofNullable(node)
        .map(CatalogueTreeNode::getChild)
        .orElse(Collections.emptyList());
}

Recursion tip: for large data sets, pass reusable objects as method parameters instead of creating new ones inside recursion.

Check Element Existence

Use HashSet for O(1) lookups rather than List.

ArrayList<String> list = new ArrayList<>();
// check if "a" exists
for (int i = 0; i < list.size(); i++) {
    if ("a".equals(elementData[i]))
        return i;
}
HashSet<String> set = new HashSet<>();
// check if "a" exists
int index = hash(a);
return getNode(index) != null;

Unified Thread Pool Management

Create a shared ThreadPoolExecutor with consistent settings.

private static volatile ThreadPoolExecutor threadPoolExecutor = null;
private static final int CORE_POOL_SIZE = 0;
private static final int MAX_MUM_POOL_SIZE = 1000;
private static final long KEEP_ALIVE_TIME = 2;
private static final TimeUnit UNIT = TimeUnit.MINUTES;
private static final int CAPACITY = 1;
private static final RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.CallerRunsPolicy();
private static final BasicThreadFactory factory = new BasicThreadFactory.Builder()
    .namingPattern("aiserviceplatform-util-thread-pool-%d").build();

public static ThreadPoolExecutor getInstance() {
    if (threadPoolExecutor == null) {
        synchronized (ThreadPoolFactory.class) {
            if (threadPoolExecutor == null) {
                threadPoolExecutor = new ThreadPoolExecutor(
                    CORE_POOL_SIZE, MAX_MUM_POOL_SIZE, KEEP_ALIVE_TIME, UNIT,
                    new ArrayBlockingQueue<>(CAPACITY), factory, HANDLER);
            }
        }
    }
    return threadPoolExecutor;
}

Bulk Data Synchronization

When syncing large tables, use temporary tables to avoid locking the main table.

String realTableName = ...;
String tempTableName = realTableName + "_temp";
createTable(tempTableName); // create temp table
boolean flag = sync(tempTableName); // sync data
if (flag) {
    dropTable(realTableName);
    alterTableName(realTableName, tempTableName); // rename temp to real
} else {
    dropTable(tempTableName);
}

Interface Parameters

Prefer using Collection<T> for method arguments to accept any collection type.

Collection<String> getNodeIds(Collection<String> ids);

Lock Granularity

Prefer fine‑grained locks such as ReentrantLock or ReentrantReadWriteLock over large synchronized blocks.

Cache Naming

Use short, hierarchical names separated by colons, e.g., module:submodule:cache.

Cache naming example
Cache naming example

@Cacheable

Configure cache TTL when using @Cacheable.

@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
    return new RedisCacheManager(
        RedisCacheWriter.lockingRedisCacheWriter(factory),
        this.getRedisCacheConfigurationWithTtl(1),
        this.getRedisCacheConfigurationMap()
    );
}

private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer hour) {
    Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
    serializer.setObjectMapper(om);
    return RedisCacheConfiguration.defaultCacheConfig()
        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
        .entryTtl(Duration.ofHours(hour));
}

public static final String REGION_LIST_BY_CODE_CACHE_KEY = "region:list";
public static final String REGION_NAME_BY_CODE_CACHE_KEY = "region:name";

private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
    Map<String, RedisCacheConfiguration> map = new HashMap<>();
    map.put(REGION_LIST_BY_CODE_CACHE_KEY, getRedisCacheConfigurationWithTtl(24));
    map.put(REGION_NAME_BY_CODE_CACHE_KEY, getRedisCacheConfigurationWithTtl(120));
    // other cache configurations ...
    return map;
}

Asynchronous Tasks

Offload time‑consuming operations to asynchronous tasks or message queues to improve response speed.

------------ END ------------

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.

Javacode qualitythread pool
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

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.