为什么我不能使用?:运算符在Java的for循环的第三个参数中?

Izu*_*ima 29 java for-loop

为什么以下代码给我一个错误?

int n = 30000; // Some number
for (int i = 0;
     0 <= n ? (i < n) : (i > n);
     0 <= n ? (i++) : (i--)) { // ## Error "not a statement" ##
    f(i,n);
}
Run Code Online (Sandbox Code Playgroud)

eis*_*eis 47

这是因为for循环已经在Java语言规范中以这种方式定义.

14.14.1陈述的基本内容

BasicForStatement:
    for ( ForInit ; Expression ; ForUpdate ) Statement

ForStatementNoShortIf:
    for ( ForInit ; Expression ; ForUpdate ) StatementNoShortIf

ForInit:
    StatementExpressionList
    LocalVariableDeclaration

ForUpdate:
    StatementExpressionList


StatementExpressionList:
    StatementExpression
    StatementExpressionList , StatementExpression
Run Code Online (Sandbox Code Playgroud)

所以它需要是一个StatementExpression或多个StatementExpressions,并StatementExpression定义为:

14.8表达式陈述

StatementExpression:
    Assignment
    PreIncrementExpression
    PreDecrementExpression
    PostIncrementExpression
    PostDecrementExpression
    MethodInvocation
    ClassInstanceCreationExpression
Run Code Online (Sandbox Code Playgroud)

0 <= n ? (i++) : (i--)不是那些,所以不被接受.i += ((0 <= n) ? 1 : -1)是一项任务,所以它有效.

  • 我感谢有人花时间引用规范.但是你知道吗*为什么*这是这样的?这不是*为什么*,这是*如何*.它就像是说:"它引发了一个错误,因为它是在源代码中实现的." (2认同)

Eri*_*ert 23

首先,我建议不要这样编写代码.代码的目的是"如果n为正,则从零计数到n,如果n为负,则从0倒数到n",但我倾向于写:

for (int i = 0; i < abs(n); i += 1)
{
    int argument = n < 0 ? -i : i;
    f(argument, n);
}
Run Code Online (Sandbox Code Playgroud)

但这不能回答你的问题,即:

为什么我不能?:在Java的for循环的第三个参数中使用运算符?

for环具有结构for ( initialization ; condition ; action ).

表达式的目的是计算值.

声明的目的是采取行动.

有些表达式在设计时都会计算一个值并采取行动. i++,i += j,new foo(),method()等.

拥有任何其他表达式来计算值并采取行动是一种糟糕的风格.这样的表达很难推理.

因此,for循环的操作仅限于那些按设计计算值并采取操作的表达式.

基本上,通过禁止此代码,编译器告诉您,您已经做出了糟糕的风格选择.b?i++:i--是一个合法的表达,但它是非常糟糕的风格,因为它使计算一个值的东西产生副作用并忽略该值.

  • @vaxquis:其次,我不关心循环中不必要的计算所引起的额外纳秒数.一个好的优化器将检测循环不变量并将它们提升出来.但更一般地说:如果没有配置文件导向的证据,对程序进行纳米优化是一种不好的做法.在C#中手动提升循环不变量实际上会导致抖动生成*较慢的*代码.您应该编写最清晰的代码,然后验证它是否符合您的性能目标. (7认同)
  • @vaxquis:首先,你显然有一个共同但奇怪的信念,即消除与临时值相关联的名称会使其"更好".我不确定这个奇怪的信念来自哪里.这种信念是否有证据证明,或者你只是断言它? (6认同)

eth*_*far 17

更换

0 <= n ? (i++) : (i--)
Run Code Online (Sandbox Code Playgroud)

i += ((0 <= n) ? 1 : -1)
Run Code Online (Sandbox Code Playgroud)

应该工作

  • -1表示没有解释的转储代码."做这个,这个并且它会起作用"对于学习者/初学者来说并不是一个好建议.你鼓励他/她任意复制/粘贴代码而不实际理解它. (20认同)
  • 虽然这是一个很好的建议,但它并没有真正回答这个问题*为什么*这种语法(在C和JavaScript中运行得非常好)在Java中应该是无效的. (12认同)