所以我们从 Java 21 库中得到了这个小枚举(实际上是从 Java 11 开始):
java.net.http.HttpClient.Version
public enum Version { HTTP_1_1, HTTP_2 }
以及客户代码中的这个小代码片段:
private static @NotNull String toStringHttpVersion(HttpClient.Version version) {
return switch (version) {
case HTTP_2 -> "HTTP/2";
case HTTP_1_1 -> "HTTP/1.1";
};
}
linter 编译器训练绝对满足上述内容,涵盖了所有情况,非常漂亮。
这似乎是未来在任何部署点都会遇到麻烦的方法,对吗?如果 Oracle 决定用
HTTP_2_1
扩展枚举,甚至将 HTTP_1_0
改造到其中,会怎么样?整个公司系统中安装的代码调用 toStringHttpVersion()
将惨死。
(为什么
HTTP_1_0
不在 enum
中,首先对我来说很神秘,感觉很破碎,枚举不应该存在,它应该是一个名为 Semver 的类的实例,或者可能是 BigDecimal
,但我离题了,无论如何,如果 HTTP 状态是“禁止”,那么 java.net.HttpClient
会抛出一个纯粹的 IOException
,这是令人蔑视的,我现在就停止。)
真的必须写这个:
private static @NotNull String toStringHttpVersion(HttpClient.Version version) {
return switch (version) {
case HTTP_2 -> "HTTP/2";
case HTTP_1_1 -> "HTTP/1.1";
default -> version.toString(); // future proof
};
}
这被 linter 标记为“默认分支是不必要的”,开发人员可能会匆忙地错过它,并得到 Google Copilot 或类似的帮助。
我是否遗漏了某些内容,或者 Java 是否需要一个关键字
futureextensible
来标记有未来扩展危险的枚举,从而允许 linter 发出警告?
抱歉,但是你的代码
private static @NotNull String toStringHttpVersion( HttpClient.Version version )
{
return switch( version )
{
case HTTP_2 -> "HTTP/2";
case HTTP_1_1 -> "HTTP/1.1";
default -> version.toString(); // future proof
};
}
可能看起来“面向未来”,但在这种情况下,我希望看到代码崩溃:
private static @NotNull String toStringHttpVersion( HttpClient.Version version )
{
return switch( version )
{
case HTTP_2 -> "HTTP/2";
case HTTP_1_1 -> "HTTP/1.1";
default -> throw new Error( "Unknown enum value for version: %s".formatted( version.name() );
};
}
关于 Linter 警告:
Annotation
会比关键字更好地完成这项工作,如果它仅用于 Linter,即使只是为已经存在的 Annotation
提供一个新值也可能完成这项工作(如果 Linter 承认)该值):@SuppressWarnings( "ExtensibleEnum" )
。
顺便说一句,Exclipse 和 IntelliJ Idea 都已经定义了
@SuppressWarnings
的值,以抑制有关明显不必要的 default
分支的警告。
关于抛出的错误:我通常使用一个为此目的定义特定
Error
的库:UnsupportedEnumValueError
,以及一个以枚举值作为参数的构造函数。