如何解决 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 无法检查转换是否有效(这是由于类型擦除),因此不会有 ClassCastExceptions转换点,这通常会使调试变得更加困难。

例如,如果您这样做了:

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<?> 作为地图的键类型。这样,在 registerdispatch 中,你可以要求 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);
}