自定义未经检查的异常不会抛出和调用方法 return
Custom unchecked exception doesn't make throwing and caller methods return
我遇到了无法在全新项目中重现的问题;它发生在针对 Spigot 1.8.8-R0.1 构建的 Bukkit 插件上。
我正在开发命令框架。
有两种类型的命令:那些只能由玩家 运行...
private Map<Command, PlayerCommand> playerCommands = new HashMap<>();
public interface PlayerCommand {
void run(Player sender, String[] args);
}
...以及控制台也可能 运行 的那些。
private Map<Command, GlobalCommand> globalCommands = new HashMap<>();
public interface GlobalCommand {
void run(CommandSender sender, String[] args);
}
为了注册命令,我实现了3种方法:
- 2 public 每个命令类型的方法,应该将每个自定义执行程序添加到其特定的
HashMap
。
public void registerCommand(String name, PlayerCommand executor) {
Command command = registerCommand(name);
// 2
playerCommands.put(command, executor);
}
public void registerCommand(String name, GlobalCommand executor) {
Command command = registerCommand(name);
// 2'
globalCommands.put(command, executor);
}
- 1 个用于它们共同逻辑的私有方法,即将它们的 Bukkit 的
CommandExecutor
属性 设置为当前实例(稍后将处理它们,将工作委托给从中获取的特定自定义执行程序地图)。
private Command registerCommand(String name) {
PluginCommand command = plugin.getCommand(name);
if (command.getExecutor() == this) {
throw new CommandAlreadyRegisteredException("The '" + name + "' command has been already registered");
}
// 1
command.setExecutor(this);
return command;
}
您可能已经注意到,客户端不能多次注册相同的命令。
为了实现这一点,我知道我可以要求地图已经包含命令,但那将是两个操作,同时使用 ==
运算符检查执行程序(它必须完全这个实例,不仅仅是 equals()
) 只是一个。
所以,对于错误的情况,我决定抛出一个未经检查的异常:
public class CommandAlreadyRegisteredException extends RuntimeException {
private static final long serialVersionUID = 1L;
protected CommandAlreadyRegisteredException(String message) {
super(message);
}
}
重点是:我原以为抛出异常会 return 在抛出它的方法中,以及在上层调用者方法中。也就是说,在这种情况下,第 1、2 和 2' 点永远不应该执行。
但他们确实被处决了!
这怎么可能?你能重现吗?为什么会这样?
我知道我可以在私有方法中 returned null
,但是这样客户端就不会知道命令已经注册了。
您需要从 Exception
而不是 RuntimeException
扩展您的自定义异常 class,因为那样会被检查,之后您可以使用代码 throw new YourException()
在任何需要抛出异常的地方。
第一次尝试注册命令:
- 您从插件中获取命令。
- 该命令没有执行者,因此检查失败。
- 然后你设置执行器。
第二次尝试:
- 您从插件中获取命令。 和你第一次得到的命令是同一个对象
- 它仍然将
this
视为其执行者。检查通过,抛出异常。
如果你只想阻止它被同一个执行者注册两次,那么绝对不需要例外:
private Command registerCommand(String name) {
PluginCommand command = plugin.getCommand(name);
if (command.getExecutor() != this) {
command.setExecutor(this);
}
return command;
}
没有错误。
为了调试,我在抛出异常后添加了一些System.out.println()
。
我只打印了一次这些断点。
没关系,因为那是允许的第一个注册,但不知为什么,我认为它们是由第二个引起的...我不知道为什么。
我遇到了无法在全新项目中重现的问题;它发生在针对 Spigot 1.8.8-R0.1 构建的 Bukkit 插件上。
我正在开发命令框架。 有两种类型的命令:那些只能由玩家 运行...
private Map<Command, PlayerCommand> playerCommands = new HashMap<>();
public interface PlayerCommand {
void run(Player sender, String[] args);
}
...以及控制台也可能 运行 的那些。
private Map<Command, GlobalCommand> globalCommands = new HashMap<>();
public interface GlobalCommand {
void run(CommandSender sender, String[] args);
}
为了注册命令,我实现了3种方法:
- 2 public 每个命令类型的方法,应该将每个自定义执行程序添加到其特定的
HashMap
。
public void registerCommand(String name, PlayerCommand executor) {
Command command = registerCommand(name);
// 2
playerCommands.put(command, executor);
}
public void registerCommand(String name, GlobalCommand executor) {
Command command = registerCommand(name);
// 2'
globalCommands.put(command, executor);
}
- 1 个用于它们共同逻辑的私有方法,即将它们的 Bukkit 的
CommandExecutor
属性 设置为当前实例(稍后将处理它们,将工作委托给从中获取的特定自定义执行程序地图)。
private Command registerCommand(String name) {
PluginCommand command = plugin.getCommand(name);
if (command.getExecutor() == this) {
throw new CommandAlreadyRegisteredException("The '" + name + "' command has been already registered");
}
// 1
command.setExecutor(this);
return command;
}
您可能已经注意到,客户端不能多次注册相同的命令。
为了实现这一点,我知道我可以要求地图已经包含命令,但那将是两个操作,同时使用 ==
运算符检查执行程序(它必须完全这个实例,不仅仅是 equals()
) 只是一个。
所以,对于错误的情况,我决定抛出一个未经检查的异常:
public class CommandAlreadyRegisteredException extends RuntimeException {
private static final long serialVersionUID = 1L;
protected CommandAlreadyRegisteredException(String message) {
super(message);
}
}
重点是:我原以为抛出异常会 return 在抛出它的方法中,以及在上层调用者方法中。也就是说,在这种情况下,第 1、2 和 2' 点永远不应该执行。 但他们确实被处决了! 这怎么可能?你能重现吗?为什么会这样?
我知道我可以在私有方法中 returned null
,但是这样客户端就不会知道命令已经注册了。
您需要从 Exception
而不是 RuntimeException
扩展您的自定义异常 class,因为那样会被检查,之后您可以使用代码 throw new YourException()
在任何需要抛出异常的地方。
第一次尝试注册命令:
- 您从插件中获取命令。
- 该命令没有执行者,因此检查失败。
- 然后你设置执行器。
第二次尝试:
- 您从插件中获取命令。 和你第一次得到的命令是同一个对象
- 它仍然将
this
视为其执行者。检查通过,抛出异常。
如果你只想阻止它被同一个执行者注册两次,那么绝对不需要例外:
private Command registerCommand(String name) {
PluginCommand command = plugin.getCommand(name);
if (command.getExecutor() != this) {
command.setExecutor(this);
}
return command;
}
没有错误。
为了调试,我在抛出异常后添加了一些System.out.println()
。
我只打印了一次这些断点。
没关系,因为那是允许的第一个注册,但不知为什么,我认为它们是由第二个引起的...我不知道为什么。