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

这个功能是否会被放入以后的Java版本中?

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


答案

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

在JDK 7中实现

该功能现已通过javac “去糖”过程实施; 使用声明中的String常量的干净,高级语法case在编译时扩展为模式后面的更复杂的代码。生成的代码使用始终存在的JVM指令。

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

在JVM中切换

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

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

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

switchString对象进行去糖时,可能会使用这两个指令。在lookupswitch对散列码的第一开关以找到的情况下的原始位置是合适的。由此产生的序数非常适合a tableswitch

两个指令都要求在编译时对分配给每个案例的整数常量进行排序。在运行时,虽然O(1)性能tableswitch通常比O(log(n))性能好lookupswitch,但需要进行一些分析来确定表是否足够密集以证明时空权衡。Bill Venners写了一篇很棒的文章,详细介绍了这一点,以及其他Java流程控制指令的内幕。

在JDK 7之前

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

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

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

当然你的枚举可能有一个’other’的条目,还有一个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帖子的完整示例,使用java enum而不是使用自定义方法。

请注意,在Java SE 7及更高版本中,您可以在switch语句的表达式中使用String对象。

public class Main {

    /**
    * @param args the command line arguments
    */
    public static void main(String[] args) {

      String current = args[0];
      Days currentDay = Days.valueOf(current.toUpperCase());

      switch (currentDay) {
          case MONDAY:
          case TUESDAY:
          case WEDNESDAY:
              System.out.println("boring");
              break;
          case THURSDAY:
              System.out.println("getting better");
          case FRIDAY:
          case SATURDAY:
          case SUNDAY:
              System.out.println("much better");
              break;

      }
  }

  public enum Days {

    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
  }

添加评论

友情链接:蝴蝶教程