你真的会用 return 吗?—— 11个值得借鉴的 return 写法

前言

return 这个关键字,相信大家每天都在用。

它就像一把锤子,敲打着我们代码里的每一个出口。

但扪心自问,我们真的把这把锤子用好了吗?

今天,不想聊什么高深莫测的设计模式,也不敢妄称"最佳实践"。

只想结合自己这些年在项目摸爬滚打中踩过的一些坑、积累的一点心得,和大家分享一些关于 return 的、或许能让我们的代码更规范、更优雅、更易读的写法。

权当抛砖引玉,希望能引发大家的一些思考。

耐心看完,你一定有所收获。

正文

1. 提前返回(卫语句):让主逻辑更清晰

这是最常见也是非常推荐的一种模式。

核心思想是:在方法开头处理掉所有"异常"或"特殊"情况,让方法的主体部分专注于核心逻辑。

反面教材 ❌:

java 复制代码
public void processData(Data data) {
    if (data != null) {
        if (data.isValid()) {
            if (checkPermission(data)) {
                // 核心逻辑开始...
                System.out.println("处理数据:" + data.getContent());
                // ...
                // 大量核心代码嵌套在这里
                // ...
                System.out.println("处理完成");
            } else {
                System.out.println("权限不足");
            }
        } else {
            System.out.println("数据无效");
        }
    } else {
        System.out.println("数据为null");
    }
}

很难评 ,嵌套过深,核心逻辑被包裹在层层 if-else 中,可读性太差。

推荐写法 ✅:

java 复制代码
public void processData(Data data) {
    if (data == null) {
        System.out.println("数据为null");
        return; // 提前返回
    }
    if (!data.isValid()) {
        System.out.println("数据无效");
        return; // 提前返回
    }
    if (!checkPermission(data)) {
        System.out.println("权限不足");
        return; // 提前返回
    }

    // --- 核心逻辑开始 ---
    // 经过前面的卫语句检查,这里的data一定是有效且有权限的
    System.out.println("处理数据:" + data.getContent());
    // ...
    // 核心代码不再嵌套,非常清晰
    // ...
    System.out.println("处理完成");
}

通过提前 return,避免了深层嵌套,让主要的处理流程更加顺畅,代码逻辑一目了然。

配得上"优雅"二字。

2. 避免 return 后的 else

if 分支中包含 return 语句时,其后的代码天然就是 else 的逻辑,无需显式写出 else

反面教材 ❌:

java 复制代码
public String getStatus(int code) {
    if (code == 0) {
        return "Success";
    } else {
        // 其他逻辑
        return "Error: " + getErrorMessage(code);
    }
}

虽然没错,但 else 显得有些多余,未免画蛇添足。

推荐写法 ✅:

java 复制代码
public String getStatus(int code) {
    if (code == 0) {
        return "Success";
    }
    // 如果 code == 0,上面的 return 已经退出方法了
    // 能执行到这里,说明 code != 0,天然就是 else 的逻辑
    return "Error: " + getErrorMessage(code);
}

代码更简洁,减少了一层不必要的缩进。

3. 简化布尔返回

直接返回布尔表达式的结果,而不是使用 if-else 返回 truefalse

反面教材 ❌:

java 复制代码
public boolean isEligible(User user) {
    if (user.getAge() >= 18 && user.isActive()) {
        return true;
    } else {
        return false;
    }
}

点评:非常啰嗦。

推荐写法 ✅:

java 复制代码
public boolean isEligible(User user) {
    return user.getAge() >= 18 && user.isActive();
}

一行搞定,清晰明了。

4. 减少不必要的临时变量

如果一个变量仅仅是为了存储即将 return 的值,可以考虑直接 return 表达式的结果。

反面教材 ❌:

java 复制代码
public int calculateSum(int a, int b) {
    int sum = a + b;
    return sum;
}

public String getUserGreeting(User user) {
    String greeting = "Hello, " + user.getName();
    return greeting;
}

sumgreeting 变量并非必需。

推荐写法 ✅:

java 复制代码
public int calculateSum(int a, int b) {
    return a + b;
}

public String getUserGreeting(User user) {
    // 如果 user.getName() 调用成本高或需要复用,临时变量可能有意义
    // 但在这个简单场景下,直接返回更简洁
    return "Hello, " + user.getName();
}

更直接。

但注意,如果表达式复杂或计算结果需要复用,还是考虑使用临时变量,可以提高可读性或效率,需要权衡。

5. 巧用三元运算符

对于简单的二选一返回逻辑,三元运算符 ?:if-else 的简洁替代。

反面教材 ❌:

java 复制代码
public String getLevel(int score) {
    String level;
    if (score >= 60) {
        level = "Pass";
    } else {
        level = "Fail";
    }
    return level;
}

推荐写法 ✅:

java 复制代码
public String getLevel(int score) {
    return score >= 60 ? "Pass" : "Fail";
}

一行代码,清晰表达了条件选择。

但是千万注意不要滥用,过分嵌套的三元运算符会降低可读性。

6. 返回空集合而非 null

方法约定返回集合类型(List, Set, Map等)时,如果没有数据,应返回空集合而不是 null

这可以避免调用方不必要的 null 检查。

反面教材 ❌:

java 复制代码
public List<String> getUsers(String department) {
    List<String> users = findUsersByDepartment(department);
    if (users.isEmpty()) { // 或者 users == null
        return null; // 调用方需要检查 null !
    }
    return users;
}

推荐写法 ✅:

java 复制代码
import java.util.Collections;
import java.util.List;

public List<String> getUsers(String department) {
    List<String> users = findUsersByDepartment(department);
    // 假设 findUsersByDepartment 可能返回 null 或空 List
    if (users == null || users.isEmpty()) {
        return Collections.emptyList(); // 返回不可变的空列表
    }
    // 或者更好的是,确保 findUsersByDepartment 内部就返回空列表而不是 null
    return users;
}

// 调用方代码,无需担心 NullPointerException
List<String> userList = service.getUsers("IT");
for (String user : userList) { // 直接遍历,安全
    System.out.println(user);
}

调用方代码更健壮、简洁,符合"防御性编程"的原则。

7. 利用 Optional 优雅处理可能缺失的值

当方法可能返回一个值,也可能什么都不返回时,使用 Optional<T> 作为返回类型比返回 null 更能明确表达这种可能性,并引导调用方正确处理。

反面教材 ❌:

java 复制代码
public User findUserById(String id) {
    // ... 查询逻辑 ...
    if (found) {
        return user;
    } else {
        return null; // 调用方必须检查 null
    }
}

// 调用方
User user = findUserById("123");
if (user != null) { // 繁琐的 null 检查
    System.out.println(user.getName());
}

推荐写法 ✅:

java 复制代码
import java.util.Optional;

public Optional<User> findUserById(String id) {
    // ... 查询逻辑 ...
    if (found) {
        return Optional.of(user);
    } else {
        return Optional.empty();
    }
}

// 调用方
findUserById("123")
    .ifPresent(user -> System.out.println(user.getName())); // 清晰地处理存在的情况

// 或者提供默认值
String userName = findUserById("123")
                    .map(User::getName)
                    .orElse("Unknown User");

Optional 强制调用者思考值不存在的情况,并通过链式调用提供了更流畅的处理方式,减少空指针风险。

但是Java的Optional非常蛋疼,如果使用时不加注意,本应返回Optional的方法,返回了null,反而会增加负担,因此团队的开发规范至关重要。

8. 循环中的提前返回

在循环中查找元素或满足某个条件时,一旦找到或满足,应立即 return,避免不必要的后续迭代。

反面教材 ❌:

java 复制代码
public Product findProductByName(List<Product> products, String name) {
    Product foundProduct = null;
    for (Product product : products) {
        if (product.getName().equals(name)) {
            foundProduct = product;
            break; // 找到后跳出循环
        }
    }
    // 循环结束后再返回
    return foundProduct;
}

需要一个额外的 foundProduct 变量,并且在循环外返回。

浪费性能。

推荐写法 ✅:

java 复制代码
public Product findProductByName(List<Product> products, String name) {
    for (Product product : products) {
        if (product.getName().equals(name)) {
            return product; // 一旦找到,立即返回
        }
    }
    // 循环正常结束,说明没找到
    return null; // 或者 Optional.empty()
}

逻辑更直接,代码更紧凑。

9. 利用 switch 表达式(Java 14+)

现在Java的 switch 表达式可以直接返回值,使得基于多分支选择的返回更加简洁。

反面教材 ❌ (传统 switch 语句):

java 复制代码
public String getWeekdayType(DayOfWeek day) {
    String type;
    switch (day) {
        case MONDAY:
        case TUESDAY:
        case WEDNESDAY:
        case THURSDAY:
        case FRIDAY:
            type = "Workday";
            break;
        case SATURDAY:
        case SUNDAY:
            type = "Weekend";
            break;
        default:
            throw new IllegalArgumentException("Invalid day: " + day);
    }
    return type;
}

推荐写法 ✅ (使用 switch 表达式):

java 复制代码
public String getWeekdayType(DayOfWeek day) {
    return switch (day) {
        case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Workday";
        case SATURDAY, SUNDAY -> "Weekend";
        // default 分支通常是必需的,除非覆盖了所有枚举常量
        // 如果逻辑确定上面的 case 已经覆盖所有情况,可以不写 default,
        // 但如果传入未覆盖的值会抛异常。
        // 或者明确处理:
        // default -> throw new IllegalArgumentException("Invalid day: " + day);
    };
}

代码量显著减少,-> 语法更直观,且 switch 表达式要求覆盖所有情况(或有 default),更安全。

10. 返回更有意义的类型(枚举或自定义对象)

避免使用魔法数字或含义模糊的字符串作为返回码,应返回定义清晰的枚举或包含状态和信息的自定义结果对象。

反面教材 ❌:

java 复制代码
public int processOrder(Order order) {
    if (order == null) return -1; // -1 代表失败
    if (!checkInventory(order)) return 1; // 1 代表库存不足
    // ... 处理 ...
    if (!paymentSuccess(order)) return 2; // 2 代表支付失败

    return 0; // 0 代表成功
}

// 调用方
int resultCode = processOrder(myOrder);
if (resultCode == 0) { ... }
else if (resultCode == 1) { ... } // 难以理解和维护

推荐写法 ✅:

java 复制代码
public enum OrderStatus { SUCCESS, FAILED_NULL_ORDER, FAILED_INVENTORY, FAILED_PAYMENT }

public OrderStatus processOrder(Order order) {
    if (order == null) return OrderStatus.FAILED_NULL_ORDER;
    if (!checkInventory(order)) return OrderStatus.FAILED_INVENTORY;
    // ... 处理 ...
    if (!paymentSuccess(order)) return OrderStatus.FAILED_PAYMENT;

    return OrderStatus.SUCCESS;
}

// 调用方
OrderStatus status = processOrder(myOrder);
if (status == OrderStatus.SUCCESS) { ... }
else if (status == OrderStatus.FAILED_INVENTORY) { ... } // 清晰易懂

返回类型本身就携带了业务含义,代码自解释,更易于维护和扩展。

11. 注意 finally 块中的 return(陷阱!)

尽量避免在 finally 块中使用 return

它会覆盖 trycatch 块中的 return 或抛出的异常,可能导致非预期的行为和难以追踪的 Bug。

反面教材 ❌ (极不推荐):

java 复制代码
public int trickyReturn() {
    try {
        System.out.println("Trying...");
        // 假设这里发生异常或正常返回 1
        // throw new RuntimeException("Oops!");
        return 1;
    } catch (Exception e) {
        System.out.println("Caught exception");
        return 2; // 试图在 catch 中返回 2
    } finally {
        System.out.println("Finally block");
        return 3; // finally 中的 return 会覆盖前面的所有返回/异常!
    }
    // 这个方法最终会返回 3,即使 try 或 catch 中有 return 或抛出异常
}

finally 的主要目的是资源清理(如关闭流、释放锁),而不是返回值。

在这里 return 会让程序行为变得诡异。

推荐写法 ✅:

java 复制代码
public int cleanReturn() {
    int result = -1; // 默认值或错误码
    Connection conn = null;
    try {
        conn = getConnection();
        // ... 使用 conn 操作 ...
        result = 1; // 操作成功
        return result; // 在 try 中返回
    } catch (SQLException e) {
        System.err.println("Database error: " + e.getMessage());
        result = -2; // 数据库错误码
        return result; // 在 catch 中返回
    } finally {
        // 只做清理工作
        if (conn != null) {
            try {
                conn.close();
                System.out.println("Connection closed.");
            } catch (SQLException e) {
                System.err.println("Failed to close connection: " + e.getMessage());
            }
        }
        // 不要在 finally 中 return
    }
}

finally 专注于它的本职工作------资源清理,让返回值逻辑在 trycatch 中清晰地处理。

结尾

return 虽小,五脏俱全。

一切的目的都是让代码更加优雅,逻辑更加清晰。

这些并非什么高深的理论,更多的是在日常写代码时,对可读性、简洁性和健壮性的追求。

希望你能写出诗一样的代码,从码农变成代码艺术家

当然,上面提到的点,有些可能在特定复杂场景下有争议(比如临时变量有时能提升可读性)。关键在于理解这些写法背后的思考:如何让代码更容易被他人(以及未来的自己)理解和维护?

希望这些粗浅的经验能给大家带来一点启发。

代码之道,与君共勉!

相关推荐
菠萝崽.39 分钟前
安装docker,在docker上安装mysql,docker上安装nginx
java·mysql·nginx·docker·软件工程·springboot·开发
狐凄2 小时前
Python实例题:使用Pvthon3编写系列实用脚本
java·网络·python
Lxinccode4 小时前
Java查询数据库表信息导出Word-获取数据库实现[1]:KingbaseES
java·数据库·word·获取数据库信息·获取kingbasees信息
元亓亓亓4 小时前
Java后端开发day36--源码解析:HashMap
java·开发语言·数据结构
sd21315124 小时前
RabbitMQ 复习总结
java·rabbitmq
码银7 小时前
Java 集合:泛型、Set 集合及其实现类详解
java·开发语言
东阳马生架构7 小时前
Nacos简介—4.Nacos架构和原理
java
柏油7 小时前
MySQL InnoDB 行锁
数据库·后端·mysql
咖啡调调。7 小时前
使用Django框架表单
后端·python·django
白泽talk7 小时前
2个小时1w字| React & Golang 全栈微服务实战
前端·后端·微服务