为什么我不能打开一个string?

为什么我不能打开一个String

这个function是否会被放到更高版本的Java中?

有人能解释为什么我不能这样做,因为在Java的switch语句的技术方式工作?

在Java SE 7中已经实现了使用String情况的开关语句,至less在第一次请求 16年之后。 没有提供明确的延迟原因,但可能与性能有关。

在JDK 7中实现

这个特性现在已经在javac 中用“脱糖”过程实现了。 在声明的case使用String常量的干净的高级语法在编译时被扩展为更复杂的代码。 生成的代码使用一直存在的JVM指令。

带有String开关在编译期间被转换为两个开关。 第一个将每个string映射到一个唯一的整数 – 它在原始开关中的位置。 这是通过首先打开标签的哈希码完成的。 相应的情况是testingstring相等的if语句; 如果散列有冲突,则testing是级联的if-else-if 。 第二个开关反映了原始源代码中的内容,但将shell标签replace为相应的位置。 这两个步骤的过程可以很容易地保留原来开关的stream量控制。

JVM中的开关

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

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

如果常量稀疏,则执行正确大小写的二进制search – lookupswitch指令。

在删除String对象的switch时,可能会使用这两个指令。 lookupswitch适合于第一次开启散列码来查找案例的原始位置。 由此产生的序数是一个天然的适合的tableswitch

这两条指令都要求在编译时分配给每个case的整数常量。 在运行时,虽然tableswitchO(1)性能一般好于tableswitchO(log(n))性能,但需要进行一些分析来确定表是否足够密集以certificate时空折衷。 Bill Venners撰写了一篇很好的文章 ,详细介绍了这一点,并详细介绍了其他Javastream程控制指令。

在JDK 7之前

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

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

如果你在你的代码中有一个可以打开string的位置,那么重构string可能是一个枚举值,你可以打开它。 当然,您可以限制列表中可能包含的string的潜在值,这可能是也可能不是所希望的。

当然你的枚举可以有一个“其他”和一个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的post,使用Java枚举的一个完整的例子,而不是使用自定义的方法。

请注意,在Java SE 7和更高版本中,您可以改用switch语句expression式中的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 } } 

基于整数的开关可以优化到非常有效的代码。 基于其他数据types的开关只能编译为一系列if()语句。

因为这个原因,C&C ++只允许在整数types上进行切换,因为对于其他types来说是毫无意义的。

C#的devise者决定风格是重要的,即使没有优势。

Java的devise者显然像C的devise者一样思考

James Curran简洁地表示:“基于整数的开关可以被优化为非常有效的代码,基于其他数据types的开关只能被编译为一系列的if()语句,因此C&C ++只允许开关整数types,因为这与其他types毫无意义。“

我的看法是,只要你开始切换非原语,就需要开始考虑“等于”与“==”。 首先比较两个string可能是一个相当长的过程,增加了上面提到的性能问题。 其次,如果有切换string,将有需要切换string忽略大小写,切换string考虑/忽略语言环境,切换string基于正则expression式….我会同意一个决定,节省了大量的时间语言开发人员需要花费less量的时间为程序员开发。

也可以显示从1.7开始直接使用String一个例子:

 public static void main(String[] args) { switch (args[0]) { 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; } } 

除了上面的好的论点外,我还会补充一点,今天很多人认为switch是Java过程的一个过时的剩余部分(回到C时代)。

我并不完全赞同这个观点,我认为在某些情况下, switch可以起到一定的作用,至less是因为它的速度,反正它比一些级联数字更好, else if我在某些代码中看到的else if

但是的确,值得研究一下你需要一个开关的情况,看看它是否不能被更多的OO所取代。 例如,Java 1.5+中的枚举,或许是HashTable或其他集合(有时我很遗憾我们没有(匿名)函数作为一等公民,就像在Lua中那样(没有开关或JavaScript),甚至是多态。

如果您不使用JDK7或更高版本,则可以使用hashCode()来模拟它。 因为String.hashCode()通常为不同的string返回不同的值,并且对于相同的string总是返回相同的值,所以它是相当可靠的(不同的string可以产生与注释中提到的@Lii相同的哈希码,比如"FB""Ea" )参见文档 。

所以,代码如下所示:

 String s = "<Your String>"; switch(s.hashCode()) { case "Hello".hashCode(): break; case "Goodbye".hashCode(): break; } 

这样,你在技术上打开一个int

或者,您可以使用以下代码:

 public final class Switch<T> { private final HashMap<T, Runnable> cases = new HashMap<T, Runnable>(0); public void addCase(T object, Runnable action) { this.cases.put(object, action); } public void SWITCH(T object) { for (T t : this.cases.keySet()) { if (object.equals(t)) { // This means that the class works with any object! this.cases.get(t).run(); break; } } } } 

多年来,我们一直在使用(n开源)预处理器。

 //#switch(target) case "foo": code; //#end 

预处理的文件被命名为Foo.jpp,并用ant脚本处理到Foo.java中。

好处是它被加工成运行在1.0上的Java(尽pipe通常我们只支持1.4)。 与使用枚举或其他变通方法进行欺骗相比,执行此操作(大量的string开关)要容易得多 – 代码更易于阅读,维护和理解。 IIRC(目前无法提供统计数据或技术推理),它比自然的Java等价物还要快。

缺点是你没有编辑Java,所以它有更多的工作stream程(编辑,处理,编译/testing),再加上一个IDE将链接回Java,这有点复杂(交换机成为一系列if / else逻辑步骤)并没有保持开关盒顺序。

我不推荐1.7以上的版本,但是如果你想编写针对早期的JVM的Java(因为Joe public很less安装最新的版本),这是非常有用的。

你可以从SVN获得它或在线浏览代码 。 你需要EBuild来build立它。

其他答案都表示这是在Java 7中添加的,并给出了早期版本的解决方法。 这个答案试图回答“为什么”

Java是对C ++过度复杂的反应。 它被devise成一个简单的干净的语言。

string在语言上有一些特殊情况处理,但我似乎很清楚,devise师们正在尽量减less特殊的shell和语法糖的数量。

因为string不是简单的基本types,所以在string之间切换相当复杂。 Java在devise时并不是一个常见的function,并且与简约devise不太吻合。 特别是因为他们已经决定不要特殊情况==string,这将是(有点)奇怪的情况下工作的地方==不。

在1.0到1.4之间,语言本身几乎一样。 Java的大部分增强function都在库中。

这一切都改变了与Java 5,语言大大延长。 在版本7和8中进一步扩展。我期望这种态度的变化是由C#

不是很漂亮,但是对于Java 6和以下版本来说,这是另一种方式:

 String runFct = queryType.equals("eq") ? "method1": queryType.equals("L_L")? "method2": queryType.equals("L_R")? "method3": queryType.equals("L_LR")? "method4": "method5"; Method m = this.getClass().getMethod(runFct); m.invoke(this); 

当你使用intellij的时候也要看一下:

文件 – >项目结构 – >项目

文件 – >项目结构 – >模块

如果有多个模块,请确保在模块选项卡中设置正确的语言级别。

Groovy是一件轻而易举的事情; 我embedded了groovy jar,并创build了一个groovy实用程序类来完成所有这些事情,以及我在Java中感到非常恼火的事情(因为我在企业中使用Java 6而陷入困境)。

 it.'p'.each{ switch (it.@name.text()){ case "choclate": myholder.myval=(it.text()); break; }}... 
 public class StringSwitchCase { public static void main(String args[]) { visitIsland("Santorini"); visitIsland("Crete"); visitIsland("Paros"); } public static void visitIsland(String island) { switch(island) { case "Corfu": System.out.println("User wants to visit Corfu"); break; case "Crete": System.out.println("User wants to visit Crete"); break; case "Santorini": System.out.println("User wants to visit Santorini"); break; case "Mykonos": System.out.println("User wants to visit Mykonos"); break; default: System.out.println("Unknown Island"); break; } } }