为什么我不能在 String 上使用 switch 语句?

新手上路,请多包涵

这个功能会被放到以后的 Java 版本中吗?

有人可以解释为什么我不能这样做,例如 Java 的技术方式 switch 声明有效吗?

原文由 Alex Beardsley 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 725
2 个回答

带有 String 案例的 Switch 语句已在 Java SE 7 中实现,距 首次请求至少 16 年。 没有提供延迟的明确原因,但这可能与性能有关。

JDK 7 中的实现

该功能现已在 javac 中实现, 并带有“脱糖”过程; 使用 String 常量的干净的高级语法 case 声明在编译时扩展为遵循模式的更复杂的代码。生成的代码使用一直存在的 JVM 指令。

A switchString 案例在编译期间被翻译成两个开关。第一个将每个字符串映射到一个唯一的整数——它在原始开关中的位置。这是通过首先打开标签的哈希码来完成的。对应的case是一个测试字符串相等性的 if 语句;如果哈希上存在冲突,则测试是级联 if-else-if 。第二个开关反映了原始源代码中的那个,但是用它们的相应位置替换了 case 标签。这个两步过程可以很容易地保留原始交换机的流量控制。

JVM 中的开关

关于 switch 的更多技术深度,您可以参考 JVM 规范,其中描述 了 switch 语句的编译。简而言之,有两种不同的 JVM 指令可用于开关,具体取决于案例使用的常量的稀疏性。两者都依赖于为每种情况使用整数常量才能有效执行。

如果常量是密集的,它们将用作指令指针表中的索引(在减去最低值之后) tableswitch 指令。

如果常量是稀疏的,则执行对正确大小写的二进制搜索 lookupswitch 指令。

在对 switchString 对象进行脱糖时,可能会使用这两条指令。 lookupswitch 适用于第一次打开hash码找到case的原始位置。生成的序号自然适合 tableswitch

这两条指令都需要在编译时对分配给每种情况的整数常量进行排序。 At runtime, while the O(1) performance of tableswitch generally appears better than the O(log(n)) performance of lookupswitch , it requires some analysis to determine whether该表足够密集以证明时空权衡是合理的。 Bill Venners 写 了一篇很棒的文章,更详细地介绍了这一点,并深入了解了其他 Java 流控制指令。

在 JDK 7 之前

在 JDK 7 之前, enum 可以近似于基于 String 的开关。这使用编译器在每个 enum 类型上生成 的静态 valueOf 方法。例如:

 Pill p = Pill.valueOf(str);
switch(p) {
  case RED:  pop();  break;
  case BLUE: push(); break;
}

原文由 erickson 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果您的代码中有一个可以打开字符串的位置,那么最好将字符串重构为可能值的枚举,您可以打开它。当然,您将可以拥有的字符串的潜在值限制为枚举中的值,这可能是需要的,也可能不需要。

当然,您的枚举可能有一个“其他”条目和一个 fromString(String) 方法,那么您可以

ValueEnum enumval = ValueEnum.fromString(myString);
switch (enumval) {
   case MILK: lap(); break;
   case WATER: sip(); break;
   case BEER: quaff(); break;
   case OTHER:
   default: dance(); break;
}

原文由 JeeBee 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题