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 

这意味着加法运算符( +- )的优先级高于左关联移位运算符( <<>>>>> )。

在我看来,事实是“大多数程序员”认为“大多数其他程序员”不知道或不记得运算符优先级,所以他们沉迷于“插入失踪”这种被称为“防御性编程”的东西括号’,只是’澄清’那个。 是否记住这个三年级的东西是一个真正的问题是另一个问题。 同样可以说,所有这些都是完全浪费时间,如果有什么事情让事情变得更糟。 我自己的观点是,尽可能避免使用冗余语法,并且计算机程序员应该知道他们编程的语言,也可能提高他们对同事的期望。