我为什么要写(正如我的同事所说):
1 2
| import static org.apache.commons.lang.math.NumberUtils.INTEGER_ONE;
if (myIntVariable == INTEGER_ONE) { ... } |
代替:
1
| if (myIntVariable == 1) { ... } |
?
我知道建议使用常量,但我认为NumberUtils.INTEGER_ONE的值永远不会改变! 所以我写1。
-
如果它是你自己的自定义常量,那么以这种方式使用是有意义的。
-
也许你可以问你的同事那个问题? 他/她可能有特殊的理由使用我们不知道的。
-
@FlorentBayle我的同事在任何地方都使用常量! 他用常数替换每个数字或字符串! 他对我的原因的回答是"文档说要使用常量!"; 是的,他太挑剔了。
-
@Michele:你问过哪些文档说使用常量?
-
相关:programmers.stackexchange.com/q/56375/88986
-
官方代码约定提到了如何处理常量。 当语言设计者有关于如何处理常数的官方指南时,无需关闭"基于意见"。
你不应该。 INTEGER_ONE名称没有比1更有意义。但是,如果此值具有其他含义(例如,一年中的月份),则使用常量(如Calendar.FEBRUARY)将使您的代码更清晰。
我可以猜测Commons Math库中的这个常量是在没有Integer缓存和自动装箱的情况下在Java 1.4中创建的,所以你可以在不同的地方重用相同的Integer对象(不是原始int)。以节省内存。所以它是出于性能原因而添加的,而不是代码清晰度。现在它已经过时了:即使你需要一个Integer对象,你也可以使用Integer.valueOf(1)或隐式自动装箱并获得缓存的自动装箱。
-
但是你不应该将==用于Integer对象。
-
对于它的价值,如果使用Calendar.FEBRUARY比1更具表现力,那么INTEGER_ONE也是出于同样的原因,它明确表示它只是一个整数而不是某种序数。虽然,我想不出一个值得区分的情况。
-
@Captain Man:没有理由说清楚一个数字是一个好的代码中的数字,所有的文字数字都是一个数字,因为所有其他数字都是由命名常量表示的。
-
具有讽刺意味的是,旧代码中的这些常量导致相反的结果因为这样的旧代码使用new Integer(1),所以它是唯一的地方,其中boxing 1使用非共享对象。
-
@Holger"这样的旧代码"是指JDK中的旧代码吗?我很想看到new Integer(1)的使用,因为我无法想象有任何使用它的理由。
-
@ Jean-FranoisSavard,这是关于Commons Math库的。
-
@TagirValeev谢谢,链接。我真的没有理由使用new Integer(1),除非你讨厌你的代码审查小组......我很好奇他们为什么不使用valueOf。
-
@ Jean-FranoisSavard,这是因为这个库保留了Java 1.4兼容性,它没有valueOf方法。
你不应该写INTEGER_ONE!你也不应该写1(见下面的例外)!
为什么?像1这样的文字被称为幻数。幻数是"具有无法解释的意义或多次出现的唯一值,可以(最好)用命名常量替换"(来自同一维基百科页面的解释)。
所以通常应该做的是将这些神奇的数字变成常量,其名称代表或解释该数字的含义。常数INTEGER_ONE没有解释其含义。
所以你真正需要做的是在这个上下文中找到值的含义,并创建一个具有该名称的常量。例如,如果1表示允许的最大线程数,则应该有一个常量:
1
| static final int MAX_NUMBER_OF_THREADS = 1; |
根据Tagir的评论编辑
如果文字本身在您编写代码的域中具有含义,则不应将其替换为命名常量。 Tagir用于计算逆元素的示例是一个很好的例子:
1 2 3
| double invert(double x) {
return 1/x;
} |
这里的文字1在数学域内的这个上下文中有意义。所以它可以按原样使用。
-
这一切都很好,但你必须自己推理将其保留在自己的变量中的理由。你不应该对所有数字都这样做,至少不是现实意义上的。
-
@insidesin哦,这是错的。你应该用几乎所有有意义的文字来做这件事。但这是一个可能接近基于意见的讨论。
-
就像当我的教授要求"很多评论"然后当你问他对很多东西的定义是什么感到不安时...然后有些人因为有太多而被标记下来。
-
这样的方法怎么样:double invert(double x) {return 1/x;}?我也应该在这里避免1吗?如何命名常数呢?
-
@TagirValeev这里文字本身在域中有意义(数学):这个计算用于得到逆元素。这是一般规则的明显例外。
-
好吧,整个这个问题对我来说似乎很明显,但有人问道。所以你应该在答案中注意到存在一些明显的例外情况。"你也不应该写1"对我来说似乎太严格了......
-
@TagirValeev我在写完评论后直接这样做了。
-
实际上,在我所知道的许多编码标准中,0和1由于充分的理由而免于No-Magic_Number规则,因为它通常不代表将来可以改变的数字,例如,某事物的存在与否(类似于布尔)
-
@MikeMB我不会根据值本身表达规则,而是基于当前域中该值是否具有隐含含义的问题。当然,值0和1通常具有这样的隐含含义。即使一个值不能改变(这是一个明确的域规则),这并不意味着不给它们一个富有表现力的名字。实际上,这完全取决于代码的可读性。
-
@Seelenvirtuose:我同意,0和1只是最常见的文字,它们本身就有明确的含义。就像你提供的例子或者例如if (size > 0)。我想没有人会要求将其写为if (size > NONE)。
-
通常认为0,1和偶尔2是可接受的。要避免的幻数是a)可能会受到未来变化的影响,或者b)具有对所有人来说都不是显而易见的含义。很少有0或1具有这些属性中的任何一个。
-
@Tagir Valeev:1/x中1常量的正确名称是IDENTITY_ELEMENT_WITH_RESPECT_TO_THE_DIVISION_BINARY_OPERATION。不要感到惊讶,我也更喜欢使用文字1 ...
-
@Holger,我认识一个开发人员,它使用更长的方法和类名。
-
@TagirValeev但老兄!标签完成!!谁在乎这个名字有多长?我仍然在~3键按下键入它! /秒
-
@basher:我讨厌在查看源代码时需要水平滚动条...
-
@Holger同意。你错过了我的/s。
-
我建议在某些代码的结构与值密切相关的许多情况下,文字也是合适的。例如,如果对double[]的某些部分进行排序的例程将接受任何大小范围,但通常会调用范围为5或更少的项目,则使用switch并使用文字常量来完成合理。如果一段代码要使用硬编码的比较序列来排序5个项目(这样的序列可能比循环快得多),用文字5标记该情况将比任何其他标识符更好。
-
t @TagirValeev在一个例子中,我们从一个数组constan中分配一个值,就像从3个元素的数组常量中的下标0处的默认值一样。 我们使用var defaultCountryIndia = countries [0]; 而不是使用0我们使用DEFAULT_COUNTRY_INDEX。 所以明天即使数组中的位置发生变化,我们也只需要修改常量文件。 从幻数0和1的例外情况来看,这是正确的吗?
我碰巧为我的公司写了风格指南,我建议如下:
Don't use hard coded,"magic" values. If a value is constant, define it as such.
Numbers such as -1, 0, 1, 2, 100 can be used in some situations.
我的例子在Objective-C中,因为这是我编写指南的语言,但规则仍然适用。
好用法
1 2 3 4 5 6 7 8 9 10
| 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; |
用法不好
1 2 3 4 5 6
| 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对象,因为它将始终返回相同的实例。
因此,在上面的场景中它可能看起来不合适,但如果你在比较时使用它,肯定会有影响。
而且,尽可能多地使用常量而不是硬编码:
它可以使您的代码易于维护。如果将来发生任何变更情况,您只能在一个地方进行更改。
代码看起来更干净,更易读。
-
我同意你的答案的第一部分,但你给出使用常量的两个一般原因并不适用于此。
-
@MikeMB我提供的不是支持我的陈述,而是作为正常的编码惯例。
-
然后我建议你重温那部分。在那一刻你要说:总是喜欢常数,在一个你不应该喜欢这个常数的问题的上下文中。
-
@MikeMB编辑,感谢您指出。从你们这里学习总是很好:)
-
重新开始你的第一段:在检查容器时,Java是否会考虑具有相同值但来自不同来源的密钥?如果是这样,那听起来很可怕。
-
@underscore_d如果你问这个: - Integer i = new Integer(1); Integer k = new Integer(1);,那么i,k是不同的对象。
-
@AnkitNigam它们可能是不同的对象,但它在HashMap或HashSet中"有影响"并不是真的,因为它们会使用.equals进行比较。
从Class NumberUtils你会看到它被定义为:
1 2
| /** Reusable Integer constant for one. */
public static final Integer INTEGER_ONE = new Integer(1) |
所以,你会看到INTEGER_ONE与1不同。它是一个已经为你构建的对象。因此,如果我们需要Integer(1)的实例,而不是创建自己的实例,则可以重用库中的一个来节省时间和内存。
这实际上取决于你的应用程序,如果你确实是int版本的1,那么,你可能更好地使用它而不是这个Integer类。
-
Integer.valueOf(int)基本上不一样吗?
您可能知道它是否永远不会改变,但如果我开始编辑您的代码我就不会...
基本上它是一种在实际代码中记录代码的方法。使用这样的常量和示例的原因是为了避免代码中的Magic Numbers及其缺点。
这就是说,你可以使用它到一个不再有利的地方,并且杂乱诱导。我倾向于为不止一次使用过的东西做这件事,或者有被我或其他人改变的概念......或者用更简单的术语来表达重要的价值观。
-
我不同意神奇的数字论点。 INTEGER_ONE总是为1。
-
@CKing INTEGER_ONE是什么意思?在世界崩溃之前你能猜出你的登录细节多少次,还是更简单?
-
这正是重点:INTEGER_ONE没有比litteral 1更具意义,因此就代码清晰度和可维护性而言,它没有任何优势。
-
然后整个问题将是无关紧要的,他的问题将是针对错误的变量命名约定而不是魔术数字。我只是给了他怀疑的好处,并假设他糟糕的变量名称是一个"滑舌"。
-
@insidesin:请注意,不是他命名该变量的人
-
是的@Holger在下面读到了我愚蠢的'doh'时刻......好吧,如果没有为你删除那就是,它适合我:|
想象一下,你有这个
1
| if (myIntVariable == 1) { ... } |
但几千次......
突然之间需要成为2。
你更容易改变什么?
编辑:在downvoting之前,我从不使用幻数的优点的角度回答,我不以任何方式(我认为这是可推断的,来到人们)建议改变库常数。
-
所以你希望OP改变Commons Math库并在那里将INTEGER_ONE设置为2?
-
所以你建议改变INTEGER_ONE == 2?
-
我认为这个问题更倾向于使用常量,而不是apache特定的INTEGER_ONE
-
@Luis:相反,第二部分显示这个问题明确是关于INTEGER_ONE
-
@MikeMB没有证据证明他的意思是他的变量很差或者没有任何帮助,在你问他之前不会有任何帮助(因此在这里没有争论,完全在围栏上,你们都不对或错)
-
@insidesin:他没有说出来自图书馆的常数。而这个常数并没有很差的命名。它的目的是作为一种特定类型(不同于小学1)。它的目的永远不是某个参数的描述性名称(这是大多数人在说"偏好常数"时所想到的)。因此,所有不直接在代码中使用1的参数因为它是一个幻数也直接应用于INTEGER_ONE,而且它更像样板,因此更不易读。 Tagir Valeev解释说,为什么从性能的角度来看也不再需要它。