如何解决 IntelliJ 突出显示的未经检查的转换问题?
How do I resolve the unchecked cast problem IntelliJ is highlighting?
上下文
我正在为我的 CQRS 应用程序构建一个命令调度程序。
相关代码
命令界面
public interface Command {
}
命令执行器界面
public interface CommandExecutor<T extends Command> {
Mono<CommandResult> execute(T command);
}
命令调度程序
public class CommandDispatcher {
private final Map<String, CommandExecutor<? extends Command>> executors = new HashMap<>();
// Example usage
public static void main(String[] args) {
CommandDispatcher dispatcher = new CommandDispatcher();
dispatcher.register(MakeRequestCommand.class.getName(), new MakeRequestCommandExecutor());
dispatcher
.dispatch(MakeRequestCommand.class.getSimpleName(), new MakeRequestCommand("Any iPhone"))
.subscribe(System.out::println);
}
public <T extends Command> void register(String commandAlias, CommandExecutor<T> executor) {
executors.put(commandAlias, executor);
}
public <T extends Command> Mono<CommandResult> dispatch(String commandAlias, T command) {
if (!executors.containsKey(commandAlias)) {
throw new RuntimeException("No executor registered for command %s".formatted(commandAlias));
}
CommandExecutor<T> executor = (CommandExecutor<T>) executors.get(commandAlias);
return executor.execute(command);
}
}
问题
以下行在 IntelliJ 中产生警告。
CommandExecutor<T> executor = (CommandExecutor<T>) executors.get(commandAlias);
Unchecked cast: 'io.freesale.application.command.CommandExecutor<capture<? extends io.freesale.application.command.Command>>' to 'io.freesale.application.command.CommandExecutor'
这是我需要关心的事情吗/有什么办法可以解决它(不抑制警告。)
我担心它突出了我设计中的缺陷。
未经检查的转换字面意思是 - Java 无法检查转换是否有效(这是由于类型擦除),因此不会有 ClassCastException
s转换点,这通常会使调试变得更加困难。
例如,如果您这样做了:
dispatcher.register(SomeTypeOfCommand.class.getName(), new SomeTypeOfCommandExecutor());
dispatcher
// we're getting the SomeTypeOfCommandExecutor, but giving it AnotherTypeOfCommand
.dispatch(SomeTypeOfCommand.class.getName(), new AnotherTypeOfCommand())
.subscribe(System.out::println);
SomeTypeOfCommandExecutor
是一个 CommandExecutor<SomeTypeOfCommand>
。如果转换被 选中 ,Java 会发现将 AnotherTypeOfCommand
转换为 CommandExecutor<SomeTypeOfCommand>
是无效的转换,并抛出一个 ClassCastException
该行:
CommandExecutor<T> executor = (CommandExecutor<T>) executors.get(commandAlias);
但是,转换实际上是未经检查的,所以 ClassCastException
只会在 之后 之后被抛出,当 SomeTypeOfCommandExecutor.execute
被调用时。此时Java可以看出传入的参数不是SomeTypeOfCommand
。这可能会导致堆栈跟踪混乱。
这就是警告警告您的内容。 IMO,这没什么好担心的,因为 executor.execute(command);
在未经检查的演员表之后不远(它是 立即 之后),所以你基本上是在“检查”无论如何,立即在下一行进行演员表。如果您想更加清楚地知道您正在检查演员表,您可以在 CommandExecutor
中添加一个方法,如下所示:
boolean canExecute(Object command);
在实现中,您只需使用 instanceof
来检查 command
。
旁注:如果每种类型的命令只能有一个命令执行器,我建议您使用 Class<?>
作为地图的键类型。这样,在 register
和 dispatch
中,你可以要求 class 类型和命令的类型必须相同,这样可以防止这样的事情发生:
.dispatch(SomeTypeOfCommand.class, new AnotherTypeOfCommand())
你会做:
private final Map<Class<? extends Command>, CommandExecutor<? extends Command>> executors = new HashMap<>();
public <T extends Command> void register(Class<T> commandAlias, CommandExecutor<T> executor) {
executors.put(commandAlias, executor);
}
public <T extends Command> Mono<CommandResult> dispatch(Class<T> commandAlias, T command) {
CommandExecutor<T> executor = (CommandExecutor<T>) executors.get(commandAlias);
if (executor == null) {
throw new RuntimeException("No executor registered for command %s".formatted(commandAlias));
}
return executor.execute(command);
}
上下文
我正在为我的 CQRS 应用程序构建一个命令调度程序。
相关代码
命令界面
public interface Command {
}
命令执行器界面
public interface CommandExecutor<T extends Command> {
Mono<CommandResult> execute(T command);
}
命令调度程序
public class CommandDispatcher {
private final Map<String, CommandExecutor<? extends Command>> executors = new HashMap<>();
// Example usage
public static void main(String[] args) {
CommandDispatcher dispatcher = new CommandDispatcher();
dispatcher.register(MakeRequestCommand.class.getName(), new MakeRequestCommandExecutor());
dispatcher
.dispatch(MakeRequestCommand.class.getSimpleName(), new MakeRequestCommand("Any iPhone"))
.subscribe(System.out::println);
}
public <T extends Command> void register(String commandAlias, CommandExecutor<T> executor) {
executors.put(commandAlias, executor);
}
public <T extends Command> Mono<CommandResult> dispatch(String commandAlias, T command) {
if (!executors.containsKey(commandAlias)) {
throw new RuntimeException("No executor registered for command %s".formatted(commandAlias));
}
CommandExecutor<T> executor = (CommandExecutor<T>) executors.get(commandAlias);
return executor.execute(command);
}
}
问题
以下行在 IntelliJ 中产生警告。
CommandExecutor<T> executor = (CommandExecutor<T>) executors.get(commandAlias);
Unchecked cast: 'io.freesale.application.command.CommandExecutor<capture<? extends io.freesale.application.command.Command>>' to 'io.freesale.application.command.CommandExecutor'
这是我需要关心的事情吗/有什么办法可以解决它(不抑制警告。)
我担心它突出了我设计中的缺陷。
未经检查的转换字面意思是 - Java 无法检查转换是否有效(这是由于类型擦除),因此不会有 ClassCastException
s转换点,这通常会使调试变得更加困难。
例如,如果您这样做了:
dispatcher.register(SomeTypeOfCommand.class.getName(), new SomeTypeOfCommandExecutor());
dispatcher
// we're getting the SomeTypeOfCommandExecutor, but giving it AnotherTypeOfCommand
.dispatch(SomeTypeOfCommand.class.getName(), new AnotherTypeOfCommand())
.subscribe(System.out::println);
SomeTypeOfCommandExecutor
是一个 CommandExecutor<SomeTypeOfCommand>
。如果转换被 选中 ,Java 会发现将 AnotherTypeOfCommand
转换为 CommandExecutor<SomeTypeOfCommand>
是无效的转换,并抛出一个 ClassCastException
该行:
CommandExecutor<T> executor = (CommandExecutor<T>) executors.get(commandAlias);
但是,转换实际上是未经检查的,所以 ClassCastException
只会在 之后 之后被抛出,当 SomeTypeOfCommandExecutor.execute
被调用时。此时Java可以看出传入的参数不是SomeTypeOfCommand
。这可能会导致堆栈跟踪混乱。
这就是警告警告您的内容。 IMO,这没什么好担心的,因为 executor.execute(command);
在未经检查的演员表之后不远(它是 立即 之后),所以你基本上是在“检查”无论如何,立即在下一行进行演员表。如果您想更加清楚地知道您正在检查演员表,您可以在 CommandExecutor
中添加一个方法,如下所示:
boolean canExecute(Object command);
在实现中,您只需使用 instanceof
来检查 command
。
旁注:如果每种类型的命令只能有一个命令执行器,我建议您使用 Class<?>
作为地图的键类型。这样,在 register
和 dispatch
中,你可以要求 class 类型和命令的类型必须相同,这样可以防止这样的事情发生:
.dispatch(SomeTypeOfCommand.class, new AnotherTypeOfCommand())
你会做:
private final Map<Class<? extends Command>, CommandExecutor<? extends Command>> executors = new HashMap<>();
public <T extends Command> void register(Class<T> commandAlias, CommandExecutor<T> executor) {
executors.put(commandAlias, executor);
}
public <T extends Command> Mono<CommandResult> dispatch(Class<T> commandAlias, T command) {
CommandExecutor<T> executor = (CommandExecutor<T>) executors.get(commandAlias);
if (executor == null) {
throw new RuntimeException("No executor registered for command %s".formatted(commandAlias));
}
return executor.execute(command);
}