当您有一个表示为数组的循环缓冲区,并且您需要环绕索引(即,当您达到可能的最高索引并递增它时),是否“更好”:
return (++i == buffer.length) ? 0: i;
或者
return ++i % buffer.length;
使用模运算符有什么缺点吗?它比第一个解决方案的可读性差吗?
编辑:
当然应该是++i而不是i++,改了。
编辑 2:
一个有趣的注意事项:我在 Doug Lea 的 ArrayBlockingQueue 实现中找到了第一行代码。
最佳答案
Update: OP has admitted in a comment that it should have been pre-increment instead. Most of the other answers missed this. There lies proof that the increment in this scenario leads to horrible readability: there's a bug, and most people couldn't see it.
最易读的版本如下:
return (i == buffer.length-1) ? 0 : i+1;
使用 ++
会给检查增加不必要的副作用(更不用说我强烈认为你应该改用预增量)
原代码有什么问题?让我们看看,好吗?
return (i++ == N) ? 0 : i; // OP's original, slightly rewritten
所以我们知道:
i
是 post 递增的,所以当i == N-1
在return
语句之前时,这将返回N
而不是立即返回 0- 这是故意的吗?大多数时候,目的是使用
N
作为唯一上限
- 这是故意的吗?大多数时候,目的是使用
- 变量名
i
按照命名约定暗示了一个局部变量,但真的是这样吗?- 由于副作用,需要仔细检查它是否是一个字段
相比之下:
return (i == N-1) ? 0 : i+1; // proposed alternative
这里我们知道:
i
不被修改,不管是局部变量还是字段- 当
i == N-1
时,返回值为0
,比较典型的场景
%
方法
或者,您也可以使用 %
版本,如下所示:
return (i+1) % N;
%
有什么问题?好吧,问题是即使大多数人认为它是 modulo 运算符,但它不是!它是余数 运算符 ( JLS 15.17.3 )。很多人经常把这个弄糊涂。这是一个经典的例子:
boolean isOdd(int n) {
return (n % 2) == 1; // does this work???
}
那个密码坏了!!!它为所有负值返回 false
!问题是 -1 % 2 == -1
,尽管在数学上 -1 = 1 (mod 2)
。
%
可能很棘手,这就是为什么我推荐使用三元运算符版本。不过,最重要的部分是消除增量的副作用。
另见
关于java - 循环增量 : Which is "better"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2801581/