Backend Development 19 min read

Java Function Coding Guidelines: Primitive Types, Parameter Classes, and Refactoring Best Practices

This article presents a series of Java function coding guidelines—including using primitive types for parameters and return values, avoiding null arrays or lists, encapsulating many parameters into objects, replacing anonymous inner classes with functions, simplifying control flow, and employing temporary variables—to improve code readability, maintainability, and robustness.

Java Captain
Java Captain
Java Captain
Java Function Coding Guidelines: Primitive Types, Parameter Classes, and Refactoring Best Practices

The article continues a series of Java coding rules aimed at improving system maintenance and longevity by providing concrete guidelines for function design and refactoring.

11. Internal Function Parameters and Return Types

11.1 Example: Use primitive types for parameters

// Call code
double price = 5.1D;
int number = 9;
double total = calculate(price, number);

// Calculation function (original)
private double calculate(Double price, Integer number) {
    return price * number;
}

Suggested solution:

// Call code
double price = 5.1D;
int number = 9;
double total = calculate(price, number);

// Calculation function (improved)
private double calculate(double price, int number) {
    return price * number;
}

11.2 Example: Use primitive types for return values

// Get order amount (original)
public double getOrderAmount(List<Product> productList) {
    double amount = 0.0D;
    for (Product product : productList) {
        if (Objects.isNull(product) || Objects.isNull(product.getPrice()) || Objects.isNull(product.getNumber())) {
            continue;
        }
        amount += calculate(product.getPrice(), product.getNumber());
    }
    return amount;
}

// Calculation function (original)
private Double calculate(double price, double number) {
    return price * number;
}

Suggested solution:

// Get order amount (improved)
public double getOrderAmount(List<Product> productList) {
    double amount = 0.0D;
    for (Product product : productList) {
        if (Objects.isNull(product) || Objects.isNull(product.getPrice()) || Objects.isNull(product.getNumber())) {
            continue;
        }
        amount += calculate(product.getPrice(), product.getNumber());
    }
    return amount;
}

// Calculation function (improved)
private double calculate(double price, double number) {
    return price * number;
}

11.3 Main Benefits

Using primitive types avoids boxing/unboxing overhead.

Parameters of primitive types eliminate the need for null checks.

Returning primitive types removes null‑check requirements for callers.

12. Avoid Returning Null Arrays or Lists

12.1 Example: Arrays

// Call code
UserVO[] users = queryUser();
if (Objects.nonNull(users)) {
    for (UserVO user : users) {
        // process user
    }
}

// Query function (original)
private UserVO[] queryUser() {
    List<UserDO> userList = userDAO.queryAll();
    if (CollectionUtils.isEmpty(userList)) {
        return null;
    }
    UserVO[] users = new UserVO[userList.size()];
    for (int i = 0; i < userList.size(); i++) {
        UserDO user = userList.get(i);
        users[i] = new UserVO();
        users[i].setId(user.getId());
        users[i].setName(user.getName());
    }
    return users;
}

Suggested solution:

// Call code
UserVO[] users = queryUser();
for (UserVO user : users) {
    // process user
}

// Query function (improved)
private UserVO[] queryUser() {
    List<UserDO> userList = userDAO.queryAll();
    if (CollectionUtils.isEmpty(userList)) {
        return new UserVO[0];
    }
    UserVO[] users = new UserVO[userList.size()];
    for (int i = 0; i < userList.size(); i++) {
        UserDO user = userList.get(i);
        users[i] = new UserVO();
        users[i].setId(user.getId());
        users[i].setName(user.getName());
    }
    return users;
}

12.2 Example: Lists

// Call code
List<UserVO> userList = queryUser();
if (Objects.nonNull(userList)) {
    for (UserVO user : userList) {
        // process user
    }
}

// Query function (original)
private List<UserVO> queryUser() {
    List<UserDO> userList = userDAO.queryAll();
    if (CollectionUtils.isEmpty(userList)) {
        return null;
    }
    List<UserVO> userVoList = new ArrayList<>(userList.size());
    for (UserDO user : userList) {
        UserVO userVo = new UserVO();
        userVo.setId(user.getId());
        userVo.setName(user.getName());
        userVoList.add(userVo);
    }
    return userVoList;
}

Suggested solution:

// Call code
List<UserVO> userList = queryUser();
for (UserVO user : userList) {
    // process user
}

// Query function (improved)
private List<UserVO> queryUser() {
    List<UserDO> userList = userDAO.queryAll();
    if (CollectionUtils.isEmpty(userList)) {
        return Collections.emptyList();
    }
    List<UserVO> userVoList = new ArrayList<>(userList.size());
    for (UserDO user : userList) {
        UserVO userVo = new UserVO();
        userVo.setId(user.getId());
        userVo.setName(user.getName());
        userVoList.add(userVo);
    }
    return userVoList;
}

12.3 Main Benefits

Guaranteeing non‑null arrays or lists eliminates unnecessary null checks in callers.

13. Encapsulate Many Parameters into a Parameter Class

When a method has too many parameters, wrap them into a dedicated class to improve readability and extensibility.

13.1 Example

public void modifyUser(Long id, String name, String phone, Integer age, Integer sex, String address, String description) {
    // implementation
}

Suggested solution:

public void modifyUser(User user) {
    // implementation
}

@Getter
@Setter
@ToString
private class User {
    private Long id;
    private String name;
    private String phone;
    private Integer age;
    private Integer sex;
    private String address;
    private String description;
}

13.2 Example: Grouped coordinates

public double getDistance(double x1, double y1, double x2, double y2) {
    // implementation
}

Suggested solution:

public double getDistance(Point point1, Point point2) {
    // implementation
}

@Getter
@Setter
@ToString
private class Point {
    private double x;
    private double y;
}

13.3 Main Benefits

Encapsulating parameters makes functions easier to extend and maintain.

It clarifies business concepts by grouping related data.

14. Replace Anonymous Inner Classes (including Lambdas) with Functions

Anonymous inner classes blur code boundaries; replace them with named functions or functional interfaces.

14.1 Example

sendWorkerSettleData(WorkerPushDataType.CHECKER, () -> {
    Date beginDate = DateUtils.addDays(currDate, -aheadDays);
    Date endDate = DateUtils.addDays(currDate, 1);
    return auditTaskDAO.statCheckerSettleData(beginDate, endDate);
});

Suggested solution:

sendWorkerSettleData(WorkerPushDataType.CHECKER, () -> statCheckerSettleData(currDate, aheadDays));

private List<WorkerSettleData> statCheckerSettleData(Date currDate, int aheadDays) {
    Date beginDate = DateUtils.addDays(currDate, -aheadDays);
    Date endDate = DateUtils.addDays(currDate, 1);
    return auditTaskDAO.statCheckerSettleData(beginDate, endDate);
}

14.2 Example: Split a complex anonymous class into multiple functional interfaces

cleanExpiredData("用户日志表", new CleanExpiredDataOperator() {
    @Override
    public List
queryExpiredDate(Integer remainDays) {
        return userDAO.queryExpiredDate(remainDays);
    }
    @Override
    public void cleanExpiredData(Date expiredDate) {
        userDAO.cleanExpiredData(expiredDate);
    }
});

Suggested solution:

cleanExpiredData("用户日志表", userDAO::queryExpiredDate, userDAO::cleanExpiredData);

private void cleanExpiredData(String tableName, QueryExpiredDateOperator queryExpiredDateOperator, CleanExpiredDataOperator cleanExpiredDataOperator) {
    // implementation
}

interface QueryExpiredDateOperator {
    List
queryExpiredDate(Integer remainDays);
}

interface CleanExpiredDataOperator {
    void cleanExpiredData(Date expiredDate);
}

14.3 Main Benefits

Defining explicit functions clarifies the code boundary of anonymous implementations.

Using lambdas or method references simplifies the code.

15. Simplify Code with Early Returns

Remove unnecessary if‑else structures and redundant variables.

15.1 Remove unnecessary if

public boolean isPassed(Double passRate) {
    if (Objects.nonNull(passRate) && passRate.compareTo(PASS_THRESHOLD) >= 0) {
        return true;
    }
    return false;
}

Suggested solution:

public boolean isPassed(Double passRate) {
    return Objects.nonNull(passRate) && passRate.compareTo(PASS_THRESHOLD) >= 0;
}

15.2 Remove unnecessary else

public double settleSalary(Long workId, int workDays) {
    if (isQualified(workId)) {
        return settleQualifiedSalary(workDays);
    } else {
        return settleUnqualifiedSalary(workDays);
    }
}

Suggested solution:

public double settleSalary(Long workId, int workDays) {
    if (isQualified(workId)) {
        return settleQualifiedSalary(workDays);
    }
    return settleUnqualifiedSalary(workDays);
}

15.3 Remove unnecessary variable

public List
queryUser(Long id, String name) {
    UserQuery userQuery = new UserQuery();
    userQuery.setId(id);
    userQuery.setName(name);
    List
userList = userDAO.query(userQuery);
    return userList;
}

Suggested solution:

public List
queryUser(Long id, String name) {
    UserQuery userQuery = new UserQuery();
    userQuery.setId(id);
    userQuery.setName(name);
    return userDAO.query(userQuery);
}

15.4 Main Benefits

Code becomes cleaner and easier to read.

16. Use Temporary Variables to Clarify Logic

Avoid deep method chaining; extract intermediate results into well‑named variables with null checks.

16.1 Example

private boolean isRichUser(User user) {
    return Objects.nonNull(user.getAccount()) &&
           Objects.nonNull(user.getAccount().getBalance()) &&
           user.getAccount().getBalance().compareTo(RICH_THRESHOLD) >= 0;
}

Suggested solution:

private boolean isRichUser(User user) {
    UserAccount account = user.getAccount();
    if (Objects.isNull(account)) {
        return false;
    }
    Double balance = account.getBalance();
    if (Objects.isNull(balance)) {
        return false;
    }
    return balance.compareTo(RICH_THRESHOLD) >= 0;
}

16.2 Example: Build user VO

public UserVO buildUser(UserDO user) {
    UserVO vo = new UserVO();
    vo.setId(user.getId());
    vo.setName(user.getName());
    if (Objects.nonNull(user.getAccount())) {
        vo.setBalance(user.getAccount().getBalance());
        vo.setDebt(user.getAccount().getDebt());
    }
    return vo;
}

Suggested solution:

public UserVO buildUser1(UserDO user) {
    UserVO vo = new UserVO();
    vo.setId(user.getId());
    vo.setName(user.getName());
    UserAccount account = user.getAccount();
    if (Objects.nonNull(account)) {
        vo.setBalance(account.getBalance());
        vo.setDebt(account.getDebt());
    }
    return vo;
}

16.3 Main Benefits

Temporary variables make business logic clearer.

They improve readability by giving meaningful names to intermediate results.

When the original call is expensive, caching the result can boost performance.

They prevent null‑pointer exceptions caused by chained calls.

17. Keep Only Required Parameters

Remove unused parameters from method signatures to simplify calls.

17.1 Example

private void modifyUserStatus(Long userId, Integer status, String unused) {
    userCache.modifyStatus(userId, status);
    userDAO.modifyStatus(userId, status);
}

Suggested solution:

private void modifyUserStatus(Long userId, Integer status) {
    userCache.modifyStatus(userId, status);
    userDAO.modifyStatus(userId, status);
}

17.2 Example: Replace object parameter with its key

private void deleteUser(User user) {
    userCache.delete(user.getId());
    userDAO.delete(user.getId());
}

Suggested solution:

private void deleteUser(Long userId) {
    userCache.delete(userId);
    userDAO.delete(userId);
}

17.3 Main Benefits

Only required parameters are kept, making the API clearer and preventing the need to construct unnecessary arguments.

In conclusion, applying these Java function coding rules—using primitive types, avoiding null collections, encapsulating parameters, replacing anonymous classes, simplifying control flow, leveraging temporary variables, and trimming method signatures—helps produce cleaner, more maintainable, and less error‑prone code.

Javabest practicescoding standardsrefactoringmaintainabilitycode readabilityfunction design
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

login 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.