病态使用常量
我为什么要写(正如我的同事所说):
import static org.apache.commons.lang.math.NumberUtils.INTEGER_ONE; if (myIntVariable == INTEGER_ONE) { ... }
代替:
if (myIntVariable == 1) { ... }
?
我知道推荐使用常量,但我认为NumberUtils.INTEGER_ONE
的值永远不会改变! 所以我写1
。
你不应该。 INTEGER_ONE
名字不会比1更有意义。但是如果这个值有一些其他的含义(例如,一年中的月份),那么使用一个常量(比如Calendar.FEBRUARY
)会使你的代码更清晰。
我可以猜测Commons Math库中的这个常量是在Java 1.4中创build的,因为没有Integercaching和自动装箱,所以它可以在不同的地方重复使用相同的Integer
对象(不是原始的int
)来节省内存。 所以它是出于性能原因而添加的,而不是为了代码清晰。 现在已经过时了:即使你需要一个Integer
对象,也可以使用Integer.valueOf(1)
或隐式自动装箱,并获得caching。
你不应该写INTEGER_ONE
! 你也不应该写1
(见下面的例外)!
为什么? 像1
这样的文字被称为幻数 。 魔术数字是“具有无法解释的意义或可能(最好)被命名常量replace的多个事件的唯一值”(来自同一维基百科页面的解释)。
所以通常应该做的是把这些魔术数字变成常量,这些常量的名字代表或解释了这个数字的含义。 常量INTEGER_ONE
不解释含义。
所以你实际上必须做的是在这个上下文中find这个值的含义,并用这个名字创build一个常量。 例如,如果1
表示允许的线程的最大数量,则应该有一个常量,例如:
static final int MAX_NUMBER_OF_THREADS = 1;
编辑按照Tagir的评论
如果文字本身在您正在编写代码的域中有意义,则不应该使用命名常量replace它。 Tagir计算逆元素的例子是一个很好的例子:
double invert(double x) { return 1/x; }
这里的数字1
在这个上下文中有一个含义。 所以可以按原样使用。
我刚刚为我的公司写了风格指南,我会build议如下:
不要使用硬编码的“魔术”值。 如果一个值是不变的,定义它是这样的。 在某些情况下,可以使用-1,0,1,2,100等数字。
我的例子在Objective-C中,因为这是我正在编写指南的语言,但规则仍然适用。
良好的用法
static NSString* const DatabaseName = @"database.name"; //Acceptable use of "2" float x = (ScreenWidth / 2) - (ImageWidth / 2); //Acceptable use of 0 for (int i = 0; i < NumberOfItems; i++) //Acceptable use of 100, but only because the variable is called "percentage" float percentage = (someObjects * 100) / allObjects.count;
使用不当
float x = (480 / 2) - (120 / 2); //We have to guess these are sizes? //Unneccessary constants. for (int i = ZERO; i < NumberOfItems; i += ONE) float percentage = (someObjects.count * 100) / 120; //What is 120?
org.apache.commons.lang.math.NumberUtils.INTEGER_ONE
它给你一个final static Integer
对象,而不是原始的int
1,并且因为它是final static
所以它作为一个常量,可以用来比较Integer
对象,因为总是会返回相同的实例。
所以在上面的情况下,它可能不太合适,但如果你在比较时使用它,肯定会有影响。
而且,尽可能多的,应该更喜欢使用硬编码的常量:
- 它可以使你的代码易于维护。 如果将来发生任何变化,只能在一个地方更换。
- 代码看起来更干净,更具可读性。
你可能知道它是否永远不会改变,但我不会,如果我开始编辑你的代码…
基本上这是一种在实际代码中logging代码的方法 。 使用这样的常量和例子的原因是为了避免代码中的幻数和它们的缺点。
这就是说,你可以使用它到一个不再有利的地步,并引起混乱。 我倾向于为不止一次使用过的东西,或者有被我或其他人改变的概念,或者用更简单的术语来说, 重要的价值观。
从类NumberUtils你会看到它被定义为:
/** Reusable Integer constant for one. */ public static final Integer INTEGER_ONE = new Integer(1)
所以,你会看到INTEGER_ONE与1不一样。它是一个已经为你构build的对象。 所以,如果我们需要一个Integer(1)
的实例,而不是自己创build,那么可以重用库中的一个节省时间和内存。
这真的取决于你的应用程序,如果你确实是什么int
版本1,那么,你可能会更好地使用,而不是这个Integer
类。
想象一下,你有这个
if (myIntVariable == 1) { ... }
但几千次…
突然间需要成为一个2。
你更容易改变?
编辑:在downvoting之前,即时回答从不使用幻数的优点的angular度来看,即时通讯不以任何方式(我认为这是推断,来人)build议改变图书馆常数。