Java为什么您的switch语句数据类型不能很长?


79

这是Sun的Java教程的摘录:

一种开关用的工作原理byteshortchar,和int原始数据类型。它还与枚举类型(在类和继承讨论)和少数特殊类作品是“包装”某些基本类型:CharacterByteShort,和Integer(在简单的数据对象讨论)。

一定有充分的理由为什么long不允许原始数据类型。有人知道这是什么吗?

Answers:


51

我认为在某种程度上,这可能是基于开关的典型用法的任意决定。

切换基本上可以通过两种方式(或原则上是组合)来实现:对于少数情况或值分散的情况,切换本质上等同于临时变量上一系列if的等效项(开启的值仅需评估一次)。对于数量或多或少连续的中等数量的情况,使用切换表(Java中的TABLESWITCH指令),从而在表中有效地查找要跳转到的位置。

这些方法中的任何一种原则上都可以使用长值而不是整数。但是我认为这可能是在实际需要之间平衡指令集和编译器的复杂性的一个实际决定:真正需要长时间切换的情况非常罕见,以至于必须将其重写为系列IF语句,或以其他方式工作(如果所讨论的长值彼此靠近,则可以在Java代码中切换减去最小值的int结果)。


我已经在Java中进行了一段时间的开发,因此我必须同意“稀有”的说法,而且直到现在,我再也没有遇到过需要/尝试开启的情况。
福斯塔2010年

3
Dimitris,我的推理并非基于对线程安全的理解,只是我认为您提出的线程安全论点不成立。
尼尔·科菲

13
有史以来最愚蠢的设计决策。我有一长串的旗帜,如果…………否则………………………………………………………………………………………………………………………………………………………………………………
m0skit0 2012年

2
我同意w / @ m0skit0。在我的情况下,其他人编写了一个使用long作为常量的API,因为这就是他们存储在数据库中的内容。现在,由于其他人的错误决定,我无法使用开关/保护套。
CodeChimp

1
我并不是说这是“世界末日”。而且,是的,有很多解决方法,但是它们看起来都像黑客一样。我的观点是,作为开发人员,我们应该始终思考过去,认为人们将如何使用我们构建的东西。在这种情况下,某人基于最初的想法“谁会诚实地拥有2 ^ 64个案例”,决定不允许长时间切换/使用案例。也许这太过简单了。也许还有其他原因导致我们无法切换多头,因为我们也没有隐私。对我来说,不支持它似乎很奇怪。
CodeChimp

21

因为他们没有在字节码中实现必要的指令,并且您确实不想编写那么多情况,无论您的代码多么“生产就绪”……

[编辑:摘自对此答案的评论,并在背景中添加了一些内容]

确切地说,2³²是很多情况,任何程序只要其方法足以容纳更多内容,那将是非常可怕的!任何语言。(我在任何语言中的任何代码中最长的功能都超过6k SLOC,是的,这是一个很大的功能switch,而且确实难以管理。)如果您真的long对只能拥有一个int或更少的位置感到困惑,那么您有两个真正的选择。

  1. 使用哈希函数主题的一些变体将压缩longint。仅当类型错误时才使用的最简单方法就是强制转换!更有用的是这样做:

    (int) ((x&0xFFFFFFFF) ^ ((x >>> 32) & 0xFFFFFFFF))
    

    在打开结果之前。您还必须弄清楚如何转换要测试的案例。但是,实际上,这仍然很可怕,因为它没有解决很多案件的真正问题。

  2. 如果要处理大量案例,一个更好的解决方案是将设计更改为使用aMap<Long,Runnable>或类似名称,以便您查找如何分配特定值。这样,您就可以将案例分为多个文件,当案例数变大时,管理起来要容易得多,尽管组织涉及的许多实现类的注册确实变得更加复杂(注释可以帮助您自动建立注册码)。

    FWIW,我是在很多年前(在整个项目过程中部分切换到新发布的J2SE 1.2)这样做的,当时,我构建了一个用于模拟大规模并行硬件的自定义字节码引擎(不,由于根本原因,重用JVM是不合适的)涉及不同的价值和执行模型),并且相对于switchC版本的代码正在使用的代码,它大大简化了代码。

重申switch一句,要想带回家,long这表明您在程序中输入了错误的类型,或者您正在构建的系统涉及很多变化,因此应该使用类。无论哪种情况,都需要重新考虑的时间。


1
但是切换的范围真的超过32位宽吗?我从未听说过需要那么多开关臂的代码。否则,您可以缩小范围(例如,通过对哈希函数的主题进行一些更改)以使某些事情起作用。或使用Map<Long,Runnable>完全不同的方式解决问题。:-)
Donal Fellows 2010年

3
@Lord Torgamus:大概是因为它很傻。想一想:为什么任何人,任何人的代码中都包含超过2 32个臂switch?想要从众多元素中选择一个有限的集合,仅表明该程序的基本设计存在错误。人们要求它只是表明**他们的设计有误
Donal Fellows 2010年

1
顺便说一句,如果有人想在这方面与我进一步争论,请先给出一个用例来打开一个长的例子。否则,我们将永远与假设争论不休……
Donal Fellows 2010年

2
@DonalFellows,另一种情况是在Android中使用ListView。虽然listViews可以有long许多行,但我具体只需要4。这是我的工作情况,long它指示要对哪一行进行操作,并且我需要根据它所在的行来做不同的事情。我想我可以转换为int,但是如果我可以修改switch变量,那会让我的生活更轻松。照原样,我只是使用ifand的字符串else if
克里斯汀·史密斯,

6
“重申一句实在的信息,想长时间打开就表明您的程序类型错误” -不,不是!拥有along并不意味着您将检查所有可能性,就像拥有anint或aString并不意味着要检查所有可能性。这意味着您拥有的值(可能很少)具有很大的范围。您可能正在检查一些简单的案例,然后default进行其余的讨论。必须进行轮班和强制转换意味着您将有丢失数据的风险。归根结底,这是一个错误的Java设计决策,而不是用户问题。
jbx

6

因为查找表索引必须为32位。


3
但是再一次,switch不必用查询表来实现。
Joachim Sauer

9
如果真是这样,他们将永远无法实现对字符串的切换(如他们目前的计划)。
Dimitris Andreou 2010年

1
@DimitrisAndreou是的,我们现在可以切换字符串:D(多年以来:P)
J. Doe

-11

在32位体系结构中,long由两个词表示。现在,想象一下如果由于同步不充分而发生什么情况,switch语句的执行观察到一个long,一次写入高32位,而另一次写入32低!它可以尝试去....谁知道呢!基本上是随机的。即使两个写入都代表switch语句的有效情况,但它们的滑稽组合可能不会导致第一个或第二个情况发生-甚至更糟的是,它可能导致另一个有效但无关的情况!

至少对于int(或更小的类型)而言,无论您搞砸了多厉害,switch语句至少会读取某人实际写的值,而不是“凭空”的值。

当然,我不知道真正的原因(已经超过15年了,我一直没有关注这么长的时间!),但是如果您意识到这种结构可能多么不安全和不可预测,您将同意这是一个绝对很好的理由不要永远对多头开关(而且只要-pun intended-会有32吨的机器,因此仍然有效)。


1
我认为这不会。需要计算打开的值,并将其存储在寄存器或堆栈中。如果该值是基于多个线程访问的数据计算的,则无论结果的宽度如何,都需要使此计算成为线程安全的。但是,一旦将结果存入寄存器或堆栈中,就只能由交换线程访问它并且是安全的。
尼尔·科菲

尼尔,您的论点很困惑:“但是,一旦结果存入寄存器或堆栈中,它就只能由交换线程访问并且是安全的”。当然,使用该值是线程安全的!但是我的观点是,由于用户代码中的同步错误该值可能已经错误。安全地使用线程错误的值没什么用处:)这个问题永远无法消除:错误的并发代码可能已经产生了“凭空产生” /错误的长值,该值随后可在开关中使用,从而导致转到从未指定的案件地址。
Dimitris Andreou 2010年

1
迪米特里斯(Dimitris),也许您的论点中有些我不理解的东西。由于用户代码中的同步错误,打开的值的确可能是错误的。但是我不认为switch语句有任何内在的特性使它比其他情况更容易实现。尽我所能,我不认为长读/写长/低字对内存的非原子性实际上不是问题。(从另一角度考虑问题:您可以基于相同的论点来决定是否不允许对long进行比较。)
Neil Coffey 2010年

人们同意,虽然长期被潜在地表示为两个单词而没有保证原子写入的潜在问题是一个普遍的问题,但在切换的情况下,这将是一个更加明显的危险。就像发送带有消息的信封一样,其中一半的地址来自一个人,一半的地址来自另一个人-最终地址可能是有效的,并且与一个完全随机的小伙子相对应,然后他会收到信封并采取相应的行动。读取垃圾并产生垃圾(就像一个错误的布尔值)是一回事,但是读取垃圾并进行随机跳转确实对我来说有点危险。
Dimitris Andreou 2010年

7
我知道这很陈旧,对此进行评论是没有根据的,但是我想强调一下,您的论点同样适用,if结果也将同样糟糕:错误的结果〜>错误的分支。创建一个长if- else-if链,而不是switch实际上会导致完全相同的结果。
Nicolai Parlog
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.