Java运算符优先级指南
误解Java运算符优先级是常见问题和微妙错误的来源。 我很想知道即使是Java语言规范也说,“建议代码不要严格依赖于这个规范。” JLS§15.7优先选择聪明 ,这方面有什么有用的指导方针吗?
以下是有关该主题的一些资源:
- JLS运营商
- JLS优先级
- Java词汇表
- 普林斯顿
- Oracle教程
- 转化和促销
- Java运算符优先级
- 评估顺序和优先顺序
- Usenet讨论
欢迎增加或更正。
就“真实世界”而言,可能公平地说:
- 有足够的程序员知道乘法/除法优先于加法/减法,在数学上就是惯例
- 几乎没有任何程序员能记住任何其他优先规则
因此,除了*/
vs +-
的具体情况之外,我实际上只是使用括号来明确定义预期的优先级。
错误的另一个相关来源是如何累积舍入错误。 这不是运算符优先顺序问题本身,而是在以算术等效方式重新排列操作数后获得不同结果时的惊喜源。 这是一个sun.com版本的David Goldberg的每个计算机科学家应该知道的浮点运算 。
引用(来自Java语言规范§15.7 )应在评估顺序的上下文中阅读。 如此处所述,该部分涉及评估顺序 ,该顺序与运算符优先级 (或关联性 ) 无关 。
优先级和关联性会影响表达式树的结构 (即哪些运算符作用于哪些操作数),而“评估顺序”仅影响表达式在计算表达式时的遍历顺序。 除非某些子表达式具有影响其他子表达式的结果(或副作用)的副作用,否则评估顺序(或“遍历顺序”)没有任何效果。
例如,如果最初x == 1,则表达式++x/++x
将评估为2/3(其计算结果为0),因为Java具有从左到右的评估顺序。 如果Java中的评估顺序是从右向左,则在评估分子之前x将增加两次,并且表达式将评估为3/2(其计算结果为1)。 如果评估顺序未定义,则表达式可以评估这些结果中的任何一个。
有问题的报价及其背景,……
Java编程语言保证运算符的操作数似乎以特定的评估顺序进行评估,即从左到右。
建议代码不要严格依赖于此规范。 当每个表达式最多包含一个副作用时,代码通常更清晰,作为其最外层的操作
…不鼓励读者依赖Java 评估顺序的左右 (如上例所示)。 它不鼓励不必要的括号。
编辑:资源: Java运算符优先级表 ,它还充当JLS各部分的索引,包含从中推断出每个优先级的语法语法。
另外,不要忘记逻辑&&和|| 是快捷操作符,避免这样的事情:
sideeffect1() || sideeffect2()
如果sideeffect1()的计算结果为true,则不会执行sideeffect2()。 &&和false也是如此。 这与优先权并不完全相关,但在这些极端情况下, 共生性也可能是一个重要的方面,通常是无关紧要的(至少就我而言)
JLS没有给出显式的运算符优先级表; 当JLS描述各种运营商时,这是隐含的。 例如, ShiftExpression
的语法是这样的:
ShiftExpression: AdditiveExpression ShiftExpression << AdditiveExpression ShiftExpression >> AdditiveExpression ShiftExpression >>> AdditiveExpression
这意味着加法运算符( +
和-
)的优先级高于左关联移位运算符( <<
, >>
和>>>
)。
在我看来,事实是“大多数程序员”认为“大多数其他程序员”不知道或不记得运算符优先级,所以他们沉迷于“插入失踪”这种被称为“防御性编程”的东西括号’,只是’澄清’那个。 是否记住这个三年级的东西是一个真正的问题是另一个问题。 同样可以说,所有这些都是完全浪费时间,如果有什么事情让事情变得更糟。 我自己的观点是,尽可能避免使用冗余语法,并且计算机程序员应该知道他们编程的语言,也可能提高他们对同事的期望。