Java Function Refactoring Practices: Common Utilities, Large Function Splitting, and Code Simplification

This article presents a comprehensive guide for Java developers on improving code quality by introducing common utility functions, splitting oversized methods, ensuring consistent block levels, encapsulating repeated logic, reducing nesting depth, and eliminating unnecessary null‑checks, each illustrated with concrete code examples and clear recommendations.

Java Captain
Java Captain
Java Captain
Java Function Refactoring Practices: Common Utilities, Large Function Splitting, and Code Simplification

In a recent technical discussion, a reader complained about poorly formatted, uncommented Java code with inconsistent naming and deep nesting. The author argues that continuous code optimization and higher quality are essential for long‑term system maintainability.

1. Use Common Utility Functions

2.1 Example 1 – Improving a null‑check

<code style="font-size: 12px"><span>thisName != <span>null</span> && thisName.<span>equals</span>(name);</span></code>

Better version:

<code style="font-size: 12px"><span>(thisName == name) || (thisName != <span>null</span> && thisName.<span>equals</span>(name));</span></code>

Recommended solution:

<code style="font-size: 12px"><span>Objects.<span>equals</span>(name, thisName);</span></code>

2.2 Example 2 – Using Apache Commons

<code style="font-size: 12px"><span>import org.apache.commons.collections4.CollectionUtils;</span>
<span>CollectionUtils.isNotEmpty(list);</span></code>

Benefits

Functional programming reduces business code and makes logic clear.

General utility functions lower the probability of bugs.

2. Split Oversized Functions

When a method exceeds 80 lines, it should be broken into smaller, well‑named functions.

3.1 Example – Refactoring a large daily‑life method

<code style="font-size: 12px"><span>// 每日生活函数</span>
<span>public void liveDaily() {</span>
<span>    // 吃饭</span>
<span>    // 吃饭相关代码几十行</span>
<span>    // 编码</span>
<span>    // 编码相关代码几十行</span>
<span>    // 睡觉</span>
<span>    // 睡觉相关代码几十行</span>
<span>}</span></code>

Refactored version:

<code style="font-size: 12px"><span>public void liveDaily() {</span>
<span>    eat();</span>
<span>    code();</span>
<span>    sleep();</span>
<span>}</span>
<span>private void eat() { /* 吃饭相关代码 */ }</span>
<span>private void code() { /* 编码相关代码 */ }</span>
<span>private void sleep() { /* 睡觉相关代码 */ }</span></code>

Benefits

Short, single‑purpose functions are easier to understand and maintain.

Long functions are hard to read, modify, and often contain hidden duplication.

3. Keep Code‑Block Levels Consistent Within a Function

Example shows that a detailed block (sleep) should not be mixed with high‑level steps (eat, code). Refactor by extracting detailed logic into its own method.

<code style="font-size: 12px"><span>public void liveDaily() {</span>
<span>    eat();</span>
<span>    code();</span>
<span>    sleep();</span>
<span>}</span>
<span>private void sleep() { /* 睡觉相关代码 */ }</span></code>

4. Encapsulate Repeated Functionality

Example of disabling users:

<code style="font-size: 12px"><span>public void disableUser() {</span>
<span>    List<Long> userIdList = queryBlackUser();</span>
<span>    for (Long userId : userIdList) {</span>
<span>        User userUpdate = new User();</span>
<span>        userUpdate.setId(userId);</span>
<span>        userUpdate.setEnable(Boolean.FALSE);</span>
<span>        userDAO.update(userUpdate);</span>
<span>    }</span>
<span>    // similar loop for expired users …</span>
<span>}</span></code>

Refactored by extracting a single helper:

<code style="font-size: 12px"><span>public void disableUser() {</span>
<span>    List<Long> userIdList = queryBlackUser();</span>
<span>    for (Long userId : userIdList) {</span>
<span>        disableUser(userId);</span>
<span>    }</span>
<span>    List<Long> expired = queryExpiredUser();</span>
<span>    for (Long userId : expired) {</span>
<span>        disableUser(userId);</span>
<span>    }</span>
<span>}</span>
<span>private void disableUser(Long userId) {</span>
<span>    User userUpdate = new User();</span>
<span>    userUpdate.setId(userId);</span>
<span>    userUpdate.setEnable(Boolean.FALSE);</span>
<span>    userDAO.update(userUpdate);</span>
<span>}</span></code>

Similar extraction is shown for order processing, audit settlement, and other repetitive patterns.

5. Reduce Function Code Levels

Early returns simplify nesting:

<code style="font-size: 12px"><span>public Double getUserBalance(Long userId) {</span>
<span>    User user = getUser(userId);</span>
<span>    if (Objects.isNull(user)) return null;</span>
<span>    UserAccount account = user.getAccount();</span>
<span>    if (Objects.isNull(account)) return null;</span>
<span>    return account.getBalance();</span>
<span>}</span></code>

Using continue to skip irrelevant loop iterations also reduces depth:

<code style="font-size: 12px"><span>public double getTotalBalance(List<User> userList) {</span>
<span>    double total = 0.0;</span>
<span>    for (User user : userList) {</span>
<span>        UserAccount account = user.getAccount();</span>
<span>        if (Objects.isNull(account)) continue;</span>
<span>        Double balance = account.getBalance();</span>
<span>        if (Objects.nonNull(balance)) total += balance;</span>
<span>    }</span>
<span>    return total;</span>
<span>}</span></code>

6. Avoid Unnecessary Null Checks

When the caller guarantees non‑null arguments, the callee can omit defensive checks, simplifying the code.

<code style="font-size: 12px"><span>private void createUser(User user) {</span>
<span>    userDAO.insert(user);</span>
<span>    userRedis.save(user);</span>
<span>}</span></code>

Similarly, builders should always return a valid object, allowing callers to use the result directly.

<code style="font-size: 12px"><span>private User buildUser(Long id, String name) {</span>
<span>    User user = new User();</span>
<span>    user.setId(id);</span>
<span>    user.setName(name);</span>
<span>    return user;</span>
<span>}</span>
<span>public void saveUser(Long id, String name) {</span>
<span>    User user = buildUser(id, name);</span>
<span>    userDAO.insert(user);</span>
<span>    userRedis.save(user);</span>
<span>}</span></code>

7. Main Benefits Across All Refactorings

Reduced code duplication and line count improve readability and maintainability.

Clear method responsibilities make business logic easier to understand.

Lower nesting depth and consistent block levels prevent “code‑heavy” sections.

Encapsulated utilities promote reuse and centralize changes.

By applying these systematic refactoring techniques, Java backend projects can achieve cleaner, more robust codebases that are easier to evolve over time.

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.

JavaBackend DevelopmentCode RefactoringSoftware qualitybest practices
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

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.