← Java 基础教程

第 12 / 40 课 · 免费教程

把配方装进方法

方法 调用与复用

90–110 分钟本章使用 JDK 21,无需预览功能。基础进阶

本课作品

制作五步下矿准备程序

会把一段指令装进有名字的方法;能从 main 调用方法并解释执行顺序;能识别重复代码并安全重构;最终把下矿准备拆成五个清楚的小技能。 前置背包:变量、条件、循环和第11课的像素房子。方法会整理已有语法,不会凭空召唤新的钻石。

开始前:建议先完成第 11 课

从重复指令到清楚的流程
  1. 提取方法定义一个准备步骤
  2. 按名调用main安排顺序
  3. 核对结果重构后行为不变

01 / 13

开始前:把示例放对地方

本章使用 JDK 21,不需要预览功能。每个普通示例都给出完整程序,按标注的文件名保存。多个示例各放在自己的文件夹,避免辅助类同名。

终端命令:把中文占位符替换成实际名称

javac -encoding UTF-8 示例文件名.java
java 示例类名

类名区分大小写。完整挑战代码若分成多段,请按顺序接在同一个文件中,不要为续段另建类。运行核对只列程序输出;需要输入的地方另给输入序列。

02 / 13

每次都重抄配方吗

阿方负责出发前检查。他把“检查镐子、装食物、带火把”复制了三遍:白天一遍、夜里一遍、同桌说再来一遍。结果火把数量改了两处,第三处仍停在旧版本。

方法像一张有名字的配方卡。把一组动作写一次,需要时用方法名调用。修改规则时只改配方卡,不必追着三只复制粘贴怪物跑。

工作台正在笑重复代码
  1. 重复多处保存同样代码
  2. 风险改漏一处,行为不一致
  3. 方法定义一次,调用多次

带着四个问题出发

  • 方法的定义和调用有什么区别?
  • 为什么 main 仍然是程序出生点?
  • 怎样给方法起一个能看懂的动作名?
  • 重构后怎样证明行为没有改变?

03 / 13

给一组指令起名字

先找完全相同或概念相同的动作,再把它们搬进方法。方法名用动词开头,例如 packFood、checkArmor、printDivider。

重复代码变成一张配方卡
  1. 先记录保存原来的输出
  2. 提取重复动作移入方法
  3. 再比较调用两次,核对六行

L12Example02.java · 完整独立示例

public class L12Example02 {
    static void prepareMining() {
        System.out.println("检查镐子");
        System.out.println("装入 16 个面包");
        System.out.println("带上 64 根火把");
    }
    public static void main(String[] args) {
        prepareMining();
        prepareMining();
    }
}

运行结果

检查镐子
装入 16 个面包
带上 64 根火把
检查镐子
装入 16 个面包
带上 64 根火把

04 / 13

定义和调用 void 方法

定义方法只是把配方写进书里;调用方法才是真的拿材料开工。下面的类可以直接编译运行。

方法由方法头和方法体组成
  1. static本例可从main直接调用
  2. void执行动作,不返回值
  3. 方法名如packFood,描述动作
  4. 方法体花括号内的指令

L12Example03.java · 完整独立示例

public class L12Example03 {
    static void packFood() {
        System.out.println("装入 16 个面包");
    }
    static void checkArmor() {
        System.out.println("检查护甲耐久");
    }
    public static void main(String[] args) {
        packFood();
        checkArmor();
    }
}

运行结果

装入 16 个面包
检查护甲耐久

05 / 13

调用顺序和返回路线

Java 遇到方法调用时,会暂时离开当前位置,进入被调用的方法。方法执行到右花括号后,程序回到调用处的下一行。

main 发出任务 方法完成后返回
  1. main打印出发
  2. ringBell调用一次,打印一声叮
  3. 再调用再次打印叮
  4. 继续回到main,打印下矿

L12Example04.java · 完整独立示例

public class L12Example04 {
    static void ringBell() { System.out.println("叮"); }
    public static void main(String[] args) {
        System.out.println("出发");
        ringBell();
        ringBell();
        System.out.println("下矿");
    }
}

运行结果

出发
叮
叮
下矿

06 / 13

一个方法只做一件事

doEverything() 听起来很强,实际像一个塞满腐肉、钻石和十七把木锄的箱子。方法最好完成一个清楚的动作,并用动词描述它。

方法名就是箱子外面的标签
  1. 检查装备checkEquipment
  2. 装食物packFood
  3. 选择矿洞chooseMine
  4. 安排顺序prepareTrip调用三个步骤

L12Example05.java · 完整独立示例

public class L12Example05 {
    static void checkEquipment() { System.out.println("检查装备"); }
    static void packFood() { System.out.println("装食物"); }
    static void chooseMine() { System.out.println("选择矿洞"); }
    static void prepareTrip() {
        checkEquipment();
        packFood();
        chooseMine();
    }
    public static void main(String[] args) {
        prepareTrip();
    }
}

运行结果

检查装备
装食物
选择矿洞

命名检查

  • 方法名用小驼峰,例如 checkArmor。
  • 名字应描述动作,不写 method1。
  • 方法过长时,找能单独命名的小步骤。

07 / 13

把像素房子拆成技能

上一课的像素房子可以先做“无参数版”重构:屋顶负责前两行,墙体负责其余五行并在格子内判断门窗。下一课再用参数让同一方法处理不同尺寸。

屋顶与墙体分工,门窗留在正确格子里
  1. printRoof输出前两行屋顶
  2. printBody逐格处理墙、门、窗
  3. main按顺序调用两个方法
  4. 核对输出与第11课一致

PixelMethods.java · 完整独立示例

public class PixelMethods {
    static void printRoof() {
        System.out.println("  ^^^^^  ");
        System.out.println(" ^^^^^^^ ");
    }
    static void printBody() {
        for (int row = 2; row < 7; row++) {
            for (int col = 0; col < 9; col++) {
                char block = ' ';
                if (col == 4 && row >= 3 && row <= 5) block = 'D';
                else if ((col == 1 || col == 7)
                        && (row == 3 || row == 4)) block = 'O';
                else if (row == 2 || row == 6 || col == 0 || col == 8)
                    block = '#';
                System.out.print(block);
            }
            System.out.println();
        }
    }
    public static void main(String[] args) {
        printRoof();
        printBody();
    }
}

运行结果

  ^^^^^  
 ^^^^^^^ 
#########
#O  D  O#
#O  D  O#
#   D   #
#########

08 / 13

复用方法和小测试

复用不是盲目多调用。每次调用都应该有明确位置,方法本身也要能单独检查。

一次写好 多处调用
  1. divider定义一条分隔线
  2. 第一次调用标题前打印
  3. 第二次调用标题后打印
  4. 小测试先验证一个方法

L12Example07.java · 完整独立示例

public class L12Example07 {
    static void divider() { System.out.println("================"); }
    public static void main(String[] args) {
        divider();
        System.out.println("方块学院");
        divider();
    }
}

运行结果

================
方块学院
================

三类检查

  • 正常:按计划调用全部方法。
  • 边界:只调用一个方法或调用两次。
  • 错误:故意拼错方法名,观察编译器提示。

09 / 13

方法故障诊所

方法类 Bug 常分两类:编译器直接拦住,或程序能跑但少做一步。第二类更会伪装,所以要核对调用清单。

三个常见方法 Bug
  1. 少调用编译成功,动作缺失
  2. 嵌套方法Java拒绝这种声明
  3. 名字拼错无法找到方法
  4. 修复一次只改一个问题

L12Example08.java · 完整独立示例

public class L12Example08 {
    static void packFood() { System.out.println("装食物"); }
    public static void main(String[] args) {
        System.out.println("出发");
    }
}

运行结果

出发

BadNestedMethod.java · 故意错误示例

public class BadNestedMethod {
    public static void main(String[] args) {
        static void checkArmor() { }
    }
}

10 / 13

挑战 蓝图 下矿准备流程

挑战 交付物是 MiningPrep.java。程序必须包含五个自定义方法,并由 main 按合理顺序调用。

五个方法组成一条出发流水线
  1. checkPickaxe检查镐子
  2. packFood装入面包
  3. packTorches装入火把
  4. wearArmor穿好护甲
  5. printPlan显示路线

建筑契约

  • 五个方法都有清楚的动作名。
  • 每个方法至少输出一条可验证信息。
  • main 只负责安排流程,不重复方法内部的输出。
  • 正常运行一次,再删除一个调用制造逻辑错误。
验收表
步骤方法验收输出
1checkPickaxe镐子耐久已检查
2packFood食物已装入
3packTorches火把已装入
4wearArmor护甲已穿好
5printPlan显示下矿路线

11 / 13

挑战 实现 五个方法排队

新建 MiningPrep.java。类名和文件名一致。这些准备方法不需要输入,也不返回值。void 表示没有返回值;static 让它们可从 static main 直接调用。两者是不同的设计选择。

完整下矿准备程序
  1. 定义五个方法保存指令
  2. 调用main安排五次调用
  3. 执行每次完成后回到main
  4. 验收依次输出五条信息

MiningPrep.java · 完整独立示例

public class MiningPrep {
    static void checkPickaxe() {
        System.out.println("镐子耐久已检查");
    }
    static void packFood() {
        System.out.println("装入 16 个面包");
    }
    static void packTorches() {
        System.out.println("装入 64 根火把");
    }
    static void wearArmor() {
        System.out.println("铁甲已穿好");
    }
    static void printPlan() {
        System.out.println("路线:主矿道 -> 补给站 -> 回家");
    }
    public static void main(String[] args) {
        checkPickaxe();
        packFood();
        packTorches();
        wearArmor();
        printPlan();
    }
}

运行结果

镐子耐久已检查
装入 16 个面包
装入 64 根火把
铁甲已穿好
路线:主矿道 -> 补给站 -> 回家

12 / 13

拓展任务与通关复盘

作业要交源代码、一次运行结果和一句 Bug 记录。只交截图不算,因为截图不会告诉你分号躲在哪里。

三档任务继续整理代码
  1. 木镐三个提示方法
  2. 铁镐房屋重构,输出不变
  3. 钻石镐四阶段挑战流程
  4. 复盘说明定义与调用的区别

三档作业

  • 木镐:写 morningTip、nightTip、dangerTip 三个提示方法,并从 main 各调用一次。
  • 铁镐:把第11课像素房子的屋顶与含门窗的墙体分别装进方法,保持输出不变。
  • 钻石镐:设计 挑战 战流程,至少包含准备、开战、第二阶段、胜利四个方法。
验收表
自评能还要练
我能区分定义和调用□□
我能解释执行顺序□□
我能把重复代码提取成方法□□

13 / 13

自己的验收记录

运行之前写预期,运行之后记录实际结果。正常案例说明程序会做事;边界案例说明它知道何时停;错误案例说明它能拒绝不合理的请求。

把证据写进记录
类别你选择的输入预期与实际
正常一个常用值或一次成功操作是否逐行一致?
边界最小值、最大值及相邻值有没有少一格、多一步?
错误非法数量、缺失对象或错误语法是否明确拒绝?状态是否保持?
  • 把一个 Bug 写成:触发条件、现象、原因、最小修复。
  • 整理一个值得记住的规则,用自己的话解释,不能只复制定义。
  • 改变一个示例,保留测试记录,让结果证明你的理解。

TAKE IT WITH YOU

下载本课 PDF

完整课文、代码、图解与练习,选择你需要的语言。