5.1 为什么要有方法
前置知识:变量、条件与循环
预计时间:20 分钟
完成标志:能从重复代码中提取一个有名字、输入和输出的方法
复制三份代码很快,后来修三遍也是真的。先给这组步骤一个名字。
方法封装一段可调用行为
在自己的练习目录中保存为 BuildDemo.java。这个程序只打印构建步骤,便于观察调用,不执行真实构建。
java
public class BuildDemo {
static void buildItem() {
System.out.println("prepare");
System.out.println("compile");
System.out.println("package");
}
public static void main(String[] args) {
buildItem();
buildItem();
buildItem();
}
}bash
mkdir -p out
javac -d out BuildDemo.java
java -cp out BuildDemo方法声明提供:
text
修饰符 返回类型 方法名 (参数列表) { 方法体 }
static void buildItem() { ... }static:方法属于类,main可在同一类中直接调用;void:正常完成时不返回一个 Java 值;buildItem:调用者使用的名字;():当前没有参数;- 方法体:每次调用执行的语句。
Java 17 的普通方法定义位于类、接口等类型中,不能在源文件顶层或另一个方法体中直接定义方法。下面为节省篇幅省略外层类:static ... { ... } 放在类体内,调用语句放在 main 等方法体内。
参数让行为接收变化
java
static void buildItem(String name, int days) {
System.out.println("构建 " + name + ",需要 " + days + " 天");
}
buildItem("标准项目", 3);
buildItem("高级项目", 5);声明中的 name 和 days 是形参;调用处的 "标准项目" 和 3 是实参表达式。调用前,Java 从左到右求值实参,再把每个结果值复制给对应形参。
返回值让调用者继续组合
java
static int materialCost(int kilograms, int pricePerKilogram) {
return Math.multiplyExact(kilograms, pricePerKilogram);
}
int cost = materialCost(4, 12);
System.out.println(cost); // 48返回类型为 int,正常路径必须返回兼容值。return 结束当前方法调用并把值交给调用者。这里用 Math.multiplyExact 让整数溢出显式失败,而不是静默回绕。
void 方法也可使用无值 return; 提前结束:
java
static void printPositive(int value) {
if (value <= 0) {
return;
}
System.out.println(value);
}提取方法不是机械消除重复
适合提取的信号:
- 同一业务规则在多处出现;
- 一段代码可以用准确动词命名;
- 需要独立测试某个计算或判断;
- 主流程被低层细节淹没。
两段文字相同不一定属于同一业务概念。若它们未来变化原因不同,强行共用方法会制造错误耦合。先判断职责,再消除重复。
输入、输出、失败构成契约
java
static int unitPrice(String material) {
if (material == null) {
throw new IllegalArgumentException("material is null");
}
return switch (material) {
case "iron" -> 12;
case "silver" -> 30;
default -> throw new IllegalArgumentException("material: " + material);
};
}专业读者查方法时通常先找:允许哪些输入、返回什么、会修改哪些外部状态、可能怎样失败。方法名和类型只能表达一部分,边界测试和简短文档补全契约。
专业速查
| 问题 | 答案 |
|---|---|
void 是“什么都不做”吗 | 不是,只表示不返回 Java 值 |
| 实参何时求值 | 调用前,从左到右 |
| 参数怎样进入方法 | 结果值复制给形参 |
return 影响哪里 | 结束当前方法调用 |
| 是否见到重复就提取 | 先确认变化原因和职责相同 |
离开这一页前
给一组重复步骤命名,列出输入、返回值、可能修改的外部状态和失败方式。若两段代码只是碰巧相似、今后会因不同原因修改,就先保留各自的职责。