Java Function Coding Guidelines: Primitive Types, Null‑Safe Returns, Parameter Encapsulation, and Code Simplification

The article outlines Java function best practices, recommending primitive types for parameters and returns, returning empty collections instead of null, grouping many arguments into parameter objects, replacing anonymous classes with named methods, using early returns, temporary variables, and limiting parameters to those truly required.

Amap Tech
Amap Tech
Amap Tech
Java Function Coding Guidelines: Primitive Types, Null‑Safe Returns, Parameter Encapsulation, and Code Simplification

This article presents a set of Java coding guidelines aimed at improving code elegance, quality, and efficiency. The recommendations are organized into several topics.

11. Use primitive types for internal function parameters and return values

Using primitive types avoids unnecessary boxing/unboxing and eliminates null‑check boilerplate.

// call site
double price = 5.1D;
int number = 9;
double total = calculate(price, number);

private double calculate(double price, int number) {
    return price * number;
}

Similarly, functions that return numeric results should use primitive return types instead of wrapper classes.

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;
}

private double calculate(double price, double number) {
    return price * number;
}

12. Never return null for arrays or collections

Returning an empty array or list removes the need for callers to perform null checks.

private UserVO[] queryUser() {
    List<UserDO> userList = userDAO.queryAll();
    if (CollectionUtils.isEmpty(userList)) {
        return new UserVO[0]; // empty array instead of null
    }
    // conversion logic …
    return users;
}

For collections, return Collections.emptyList() when there is no data.

private List<UserVO> queryUser() {
    List<UserDO> userList = userDAO.queryAll();
    if (CollectionUtils.isEmpty(userList)) {
        return Collections.emptyList();
    }
    // conversion logic …
    return userVoList;
}

13. Encapsulate many parameters into a parameter object

When a method has many arguments, create a dedicated class to hold them. This improves maintainability and extensibility.

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;
}

For geometric calculations, replace four primitive arguments with a Point object.

public double getDistance(Point p1, Point p2) {
    // implementation …
}

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

14. Replace anonymous inner classes (including lambdas) with explicit functions

Extract the logic into a named method and pass the method reference, which clarifies the code boundary.

// original anonymous inner class
sendWorkerSettleData(WorkerPushDataType.CHECKER, () -> {
    Date begin = DateUtils.addDays(currDate, -aheadDays);
    Date end = DateUtils.addDays(currDate, 1);
    return auditTaskDAO.statCheckerSettleData(begin, end);
});

// refactored version
sendWorkerSettleData(WorkerPushDataType.CHECKER, this::statCheckerSettleData);

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

Complex anonymous classes can be split into multiple functional interfaces and passed as method references.

cleanExpiredData("user_log", userDAO::queryExpiredDate, userDAO::cleanExpiredData);

private void cleanExpiredData(String table, QueryExpiredDateOperator queryOp, CleanExpiredDataOperator cleanOp) {
    // implementation …
}

interface QueryExpiredDateOperator { List<Date> queryExpiredDate(Integer remainDays); }
interface CleanExpiredDataOperator { void cleanExpiredData(Date expiredDate); }

15. Simplify code with early returns and remove unnecessary branches

public boolean isPassed(Double passRate) {
    return Objects.nonNull(passRate) && passRate.compareTo(PASS_THRESHOLD) >= 0;
}
public double settleSalary(Long workId, int workDays) {
    if (isQualified(workId)) {
        return settleQualifiedSalary(workDays);
    }
    return settleUnqualifiedSalary(workDays);
}

Eliminate superfluous else blocks and temporary variables when they do not add clarity.

16. Use temporary variables to break long method‑call chains

Storing intermediate results in well‑named variables improves readability and prevents NullPointerExceptions.

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;
}

Similarly, when building a VO from a DO, retrieve the account once and reuse it.

public UserVO buildUser(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;
}

17. Keep only the parameters a function really needs

Remove unused arguments and, when possible, replace object parameters with the specific fields required.

// before – unused parameter
private void modifyUserStatus(Long userId, Integer status, String unused) { … }
// after – only needed parameters
private void modifyUserStatus(Long userId, Integer status) { … }

// before – object parameter
private void deleteUser(User user) {
    userCache.delete(user.getId());
    userDAO.delete(user.getId());
}
// after – use the id directly
private void deleteUser(Long userId) {
    userCache.delete(userId);
    userDAO.delete(userId);
}

18. Postscript

The author invites the community to contribute additional insights and examples to evolve this Java coding guideline into a comprehensive standard.

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.

Javabest practicescoding standards
Amap Tech
Written by

Amap Tech

Official Amap technology account showcasing all of Amap's technical innovations.

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.