Repository navigation
switch and try
本教程面向已经能写出基础 HimDSL 脚本的用户。 This tutorial targets users who can already write basic HimDSL scripts.
我们假设你熟悉变量、函数、if、for、while 的写法。 We assume you are familiar with variables, functions, if, for, and while.
本教程覆盖三部分:try-catch-finally、switch-case、break 与 continue。 This tutorial covers three parts: try-catch-finally, switch-case, and break/continue.
脚本运行中会出现各种意外:玩家掉线、文件不存在、参数非法。 Many unexpected things happen during script execution: players disconnect, files go missing, arguments are invalid.
如果不做处理,任何异常都会中止整个脚本。 Without handling, any exception will abort the entire script.
try-catch-finally 让你可以捕获错误、优雅降级、并确保清理逻辑一定执行。 try-catch-finally lets you catch errors, degrade gracefully, and guarantee cleanup logic always runs.
try 块放可能出错的代码。 The try block holds code that may fail.
catch 块在捕获到异常时执行。 The catch block runs when an exception is caught.
finally 块无论是否出错都会执行。 The finally block always runs regardless of errors.
形式一:catch (e) —— 捕获一切异常。 Form 1: catch (e) — catches any exception.
形式二:catch (ExceptionType e) —— 只捕获指定类型。 Form 2: catch (ExceptionType e) — catches only the specified type.
类型匹配遵循 Java 规则,父类能捕获子类。 Type matching follows Java rules: a parent type catches its subclasses.
e.message:异常的消息文本,永不为 null。 e.message: the exception message text, never null.
e.type:异常的简单类名,例如 RuntimeException。 e.type: the exception's simple class name, e.g. RuntimeException.
e.fulltype:异常的全限定名。 e.fulltype: the exception's fully qualified name.
e.stacktrace:完整的堆栈字符串。 e.stacktrace: the complete stack trace string.
e.printStackTrace():把堆栈打印到服务器日志。 e.printStackTrace(): prints the stack trace to the server log.
finally 用于释放资源,比如关闭文件句柄。 finally is used to release resources, such as closing file handles.
即使 try 里 return 了,finally 依然会先执行。 Even if try returns, finally still executes first.
void readConfig() {
int fh = 0;
try {
fh = fopen("wwwwwwwwwconfig.json", "r");
var content = fread(fh);
} catch (e) {
ply.sendMessage("读取失败: " + e.message);
} finally {
if (fh > 0) {
fclose(fh);
}
}
}
如果 finally 里有 return,它会覆盖 try 的返回值。 If finally contains a return, it overrides the try's return value.
这是 Java 的语义,HimDSL 完全照抄。 This is Java semantics, and HimDSL follows it exactly.
int tricky() {
try {
return 1;
} finally {
return 2;
}
}
// 调用 tricky() 得到 2,不是 1
// Calling tricky() yields 2, not 1
当脚本使用当前级别禁止的能力时,会抛出 PermissionDeniedException。 When a script uses a capability forbidden at its level, a PermissionDeniedException is thrown.
这个异常无法被任何 catch 捕获。 This exception cannot be caught by any catch.
finally 会正常执行,但 catch 里的代码不会运行。 finally still runs, but the catch body does not.
try {
runcmd("CONSOLE", "op someone"); // sandbox 下会被拒
} catch (e) {
// 这里的代码永远不会执行
// Code here never runs
} finally {
// 这里的代码依然会执行
// Code here still runs
}
这么设计是为了防止脚本吞掉权限日志。 This design prevents scripts from swallowing permission logs.
如果 catch 块自己抛异常,原异常会丢失。 If the catch block itself throws, the original exception is lost.
上层看到的将是 catch 里抛出的那个。 The upper layer sees the exception thrown inside catch.
建议在 catch 中避免调用可能失败的操作。 Avoid calling failure-prone operations inside catch.
catch 从上到下匹配,第一个命中即执行。 catch matches top-to-bottom; the first match wins.
子类异常必须写在父类前面。 Subclass exceptions must be written before parent exceptions.
写反了会导致子类的 catch 永远不生效。 If reversed, the subclass catch will never trigger.
如果 finally 里写了 return,即使 try 抛了异常也会被吞掉。 If finally contains a return, any exception from try is swallowed.
这通常不是你想要的行为,请谨慎使用。 This is usually not what you want; use it with caution.
当你需要根据一个值分支到多种情况时,switch 比连续 if-else 更清晰。 When you need to branch on a value into multiple cases, switch is clearer than a chain of if-else.
它也更接近配置驱动的思维方式。 It also matches a configuration-driven mindset better.
switch 后面的括号里放被比较的值。 The parentheses after switch hold the value being compared.
case 是具体的匹配值,default 是兜底分支。 case holds a specific match value; default is the fallback branch.
void handleItem(string type) {
player p = @p;
switch (type) {
case "apple":
p.sendMessage("你拿到了苹果");
break;
case "diamond":
p.sendMessage("闪闪发光");
break;
default:
p.sendMessage("普通物品: " + type);
}
}
如果 case 后不写 break,会继续执行下一个 case。 If you omit break after a case, execution continues into the next case.
这叫做 fall-through,是 Java 的经典语义。 This is called fall-through, classic Java semantics.
多个 case 共享同一段代码时非常有用。 It is very useful when several cases share the same code.
void combo(int code) {
int bonus = 0;
switch (code) {
case 1:
case 2:
bonus = bonus + 10;
case 3:
bonus = bonus + 5;
break;
case 4:
bonus = 100;
break;
}
Bukkit.getServer().getLogger().info("奖励: " + bonus);
}
code 为 1 或 2 时会先加 10 再加 5,最终 15。 When code is 1 or 2, it adds 10 then 5, ending at 15.
code 为 3 时只加 5。 When code is 3, it adds only 5.
数字:整数和浮点数都可以比较。 Numbers: both integers and floats can be compared.
字符串:直接比较文本内容。 Strings: compares text content directly.
枚举:可以和枚举常量匹配,也可以和字符串比较。 Enums: can match enum constants, or compare with strings.
这是最常见的错误。 This is the most common mistake.
每个 case 后面如果没有 break,会继续往下执行。 Without break after each case, execution flows downward.
有时候这是故意的,但更多时候是 bug。 Sometimes intentional, but more often a bug.
case 后面可以写任意表达式,不只是常量。 Any expression can follow case, not just constants.
但匹配扫描阶段只求值一次,命中后不再计算后续 case。 But evaluation happens only during the match scan; after a match, later case expressions are not evaluated.
这意味着 case 里的函数调用不会反复执行。 This means function calls inside case won't run repeatedly.
default 的位置不影响匹配逻辑。 The position of default does not affect matching logic.
匹配失败时会跳到 default 的位置,然后从上往下执行。 On match failure, execution jumps to default's position, then runs downward.
如果 default 不在最后,可能会 fall-through 到它后面的 case。 If default is not last, it may fall through to the case after it.
switch 本身不是循环,continue 会往上找最近的循环。 switch itself is not a loop; continue looks upward for the nearest loop.
如果没有外层循环,continue 什么也不做。 If there is no enclosing loop, continue does nothing.
for (int i = 0; i < 10; i = i + 1) {
switch (i) {
case 5:
continue; // 跳到 for 的下一轮
default:
ply.sendMessage("i = " + i);
}
}
本语言不支持 case 1 -> ... 这种写法。
This language does not support case 1 -> ....
也不支持 yield。 Nor does it support yield.
请老老实实用传统的 case ... : ... break; 结构。 Please use the classic case ... : ... break; structure.
break 跳出最近的循环或 switch。 break exits the nearest loop or switch.
continue 跳到最近的循环的下一轮。 continue jumps to the next iteration of the nearest loop.
在 switch 里使用 break,只会跳出 switch 本身。 Using break inside switch exits only the switch itself.
void nested(int a, int b) {
switch (a) {
case 1:
switch (b) {
case 10:
ply.sendMessage("内部命中");
break; // 只跳出内层
}
ply.sendMessage("继续外层");
break; // 跳出外层
}
}
内层 break 不会穿透到外层。 The inner break does not leak to the outer switch.
在可能失败的操作外层包 try。 Wrap potentially failing operations in try.
把资源释放放在 finally。 Put resource release in finally.
switch 每个 case 后要么 break,要么明确注释说明贯穿是故意的。 After each case in switch, either break or add a comment explaining the intentional fall-through.
catch 里不要忽略异常,至少记录日志。 Do not silently ignore exceptions in catch; at least log them.
嵌套太深的 try 或 switch 应该拆成函数。 Deeply nested try or switch blocks should be split into functions.
问:try 里可以有 return 吗? Q: Can try contain a return?
答:可以,finally 会先执行,然后才是 return。 A: Yes; finally runs first, then the return happens.
问:catch 里可以有 return 吗? Q: Can catch contain a return?
答:可以,finally 依然会执行。 A: Yes; finally still runs.
问:没有 catch 只有 finally 合法吗? Q: Is it legal to have finally without catch?
答:合法,等价于 try { ... } finally { ... }。 A: Yes, equivalent to try { ... } finally { ... }.
问:switch 里能声明变量吗? Q: Can I declare variables inside switch?
答:可以,作用域从声明处到 switch 结束。 A: Yes; the scope runs from the declaration point to the end of the switch.
问:能否 break 出多层循环? Q: Can I break out of multiple loops at once?
答:不支持带标签的 break,需要用一个标志变量模拟。 A: Labeled break is not supported; simulate it with a flag variable.
try-catch-finally 让你的脚本能优雅地处理错误。 try-catch-finally lets your scripts handle errors gracefully.
switch-case 让多分支逻辑更清晰。 switch-case makes multi-branch logic clearer.
break 和 continue 控制循环与分支的流向。 break and continue control the flow of loops and branches.
把它们组合起来,可以写出健壮、可维护的脚本。 Combining them lets you write robust, maintainable scripts.
祝你编写愉快。 Happy scripting.
- 首页 / Home
- 安装与快速开始 / Installation & Quick Start
- 第一个脚本 / Your First Script
- 命令速查 / Command Reference
- 自动执行脚本 / Auto-run Scripts
- 定义函数 / Defining Functions
- 函数重载 / Function Overloading
- Lambda 表达式 / Lambda Expressions
- 函数式接口 / Functional Interfaces
- 选择器总览 / Selectors Overview
- 选择器过滤器 / Selector Filters
- EntityRef 引用 / EntityRef
- 占位符参考 / Placeholders Reference
- PlaceholderAPI 桥接 / PAPI Bridge
- 创建 GUI / Creating a GUI
- GUISlot 槽位 / GUISlot
- 点击回调 / Click Callbacks
- onClose 回调 / onClose Callback
- GUI 刷新 / GUI Refresh
- 数学函数 / Math Built-ins
- 高精度计算 / BigDecimal Built-ins
- 字符串函数 / String Built-ins
- 集合函数 / Collection Built-ins
- 文件 I/O / File I/O
- 命令与 sleep / Commands & sleep