当你有一个循环缓冲区表示为一个数组,并且你需要索引环绕时(即,当你达到最高可能的索引并增加它时),它是否"更好":
return (++i == buffer.length) ? 0: i;
Run Code Online (Sandbox Code Playgroud)
要么
return ++i % buffer.length;
Run Code Online (Sandbox Code Playgroud)
使用模运算符有什么缺点吗?它比第一个解决方案的可读性差吗?
编辑:
当然它应该是++ i而不是i ++,改变了.
编辑2:
一个有趣的说明:我在DougBa的ArrayBlockingQueue实现中找到了第一行代码.
pol*_*nts 10
更新:OP在评论中承认它应该是预先增量的.大多数其他答案错过了这个.有证据表明,这种情况的增加导致可怕的可读性:有一个错误,大多数人都看不到它.
最易读的版本如下:
return (i == buffer.length-1) ? 0 : i+1;
Run Code Online (Sandbox Code Playgroud)
使用++会给支票带来不必要的副作用(更不用说我强烈认为你应该使用预增量)
原始代码有什么问题?我们来看看,好吗?
return (i++ == N) ? 0 : i; // OP's original, slightly rewritten
Run Code Online (Sandbox Code Playgroud)
所以我们知道:
i是后增量的,所以当i == N-1在return语句之前,这将返回N而不是立即换行到0
N作为独占上限使用i通过命名约定建议局部变量,但它真的吗?
相比下:
return (i == N-1) ? 0 : i+1; // proposed alternative
Run Code Online (Sandbox Code Playgroud)
在这里我们知道:
i 未修改,无论是局部变量还是字段都无关紧要i == N-1返回值0,这是更典型的情况%方法或者,您也可以使用以下%版本:
return (i+1) % N;
Run Code Online (Sandbox Code Playgroud)
有什么问题%?好吧,问题是即使大多数人认为它是模运算符,但它不是!它是余数运算符(JLS 15.17.3).很多人经常对此感到困惑.这是一个经典的例子:
boolean isOdd(int n) {
return (n % 2) == 1; // does this work???
}
Run Code Online (Sandbox Code Playgroud)
那段代码坏了!!! 它返回false所有负值!问题在于-1 % 2 == -1,虽然是数学上的-1 = 1 (mod 2).
%可能很棘手,这就是我推荐三元运算符版本的原因.但最重要的是消除增量的副作用.
不要让我在两个选项中进行选择,这两个选项都包含后增量(*)和表达式评估.我会说"没有".
(*)更新:后来被修复为preincrement.