这是一个完善的惯例,应避免使用魔法数字。但复杂的条件公式中的幻数呢?例如:
int result = 0;
if (level <= 50) {
result = (int) (Math.pow(level, 3) * (100 - level) / 50);
}
else if (level <= 68 && level > 50) {
result = (int) (Math.pow(level, 3) * (150 - level) / 100);
}
else if (level <= 98 && level > 68) {
result = (int) (Math.pow(level, 3) * ((1911 - 10 * level) / 3) / 500);
}
else if (level < 100 && level > 98) {
result = (int) (Math.pow(level, 3) * (160 - level) / 100);
}
return result;
在这种情况下,最好只说'#34;尽可能避免使用魔法数字&#34;?我也在eclipse中使用CheckStyle来帮助向我显示我可能错过了一个真正的幻数。但是,没有办法禁用某些数字的检查而不是其他数字。
答案 0 :(得分:5)
我认为所有魔法数字都应该声明为常量或正确记录。
首选声明文件。
否则,开发人员不清楚这些数字是什么以及它们为什么存在。
答案 1 :(得分:2)
这不仅需要用命名常量替换幻数,我建议使用一些命名的中间变量。例如,((1911 - 10 * level) / 3) / 500)
的含义到底是什么?应将其分配给具有有意义名称的变量。这是社会保障金和年龄吗?
OP不理解数字或等式的事实回答了这个问题。他将如何支持此代码?
答案 2 :(得分:0)
我会先尝试简化代码。
int l3 = level * level * level;
return level <= 50 ? l3 * (100 - level) / 50 :
level <= 68 ? l3 * (150 - level) / 100 :
level <= 98 ? l3 * ((1911 - 10 * level) / 3) / 500 :
level < 100 ? l3 * (160 - level) / 100 : 0;
然后我会看看为什么如果等级> = 100,结果为0。
由于这看起来是随意的,因此你可能很难解释这些神奇的数字,因为你可能已经制作了它们,但同样你可能会发现你可以简化公式,使其更容易计算和解释,但仍然具有所需的形状。 / p>
答案 3 :(得分:0)
这有点像风格和品味。一般建议是:当从上下文中明显看出你的意思和原因时,或者当它们的使用本身就是它们的定义时 - 也就是说,当数字的含义和原因没有其他解释时,请使用幻数。例如,如果我定义一个函数:
0 if x < 28 else 1
并没有更具体的说明这个数字而不是“我用来定义我的函数的阈值”并且在你的程序中没有其他常量等于28并且永远不会,那么你可能会把它保留为是
在您的情况下,您可能通过此公式定义这些阈值,并且没有任何关于它们的说法,那么您可以将它们保留原样。
如果您可以为该号码指定一个名称和/或评论该号码具有此值的原因,那么使用名称总是更好:
var age = 52; // my age
var code = 52; // my country's long distance code
即使你对一个数字没什么可说的,最好给它一个名字,因为如果你有两个这样的数字,你以后就不会知道它们是否是独立的。即使现在你没有平等,有一天你可能会。在上面的示例中,明年我将转为53并且必须修改公式:
a = 52 * x + y + z + 52;
但是这两个中哪一个是我的年龄,哪个是代码?一年前,当我写这个程序时,它是
a = 51 * x + y + z + 52;
对我来说很明显哪个是我的年龄,哪个是我的代码,但是在我52岁之后并且相应地修改了程序!
答案 4 :(得分:0)
你可以尝试类似下面的东西:(它没有精炼,尝试提出一个单一的公式/方程式,并根据检查替换变量中的值)
int d = 1;
int x = 3;
int l = 1;
int f = 1;
int y = 0;
if (level <= 50) {
y = 100;
d = 50;
} else if (level <= 68 && level > 50) {
y = 150;
d = 100;
} else if (level <= 98 && level > 68) {
y = 1911;
l = 10;
f = 500;
d=3;
} else if (level < 100 && level > 98) {
y = 160;
d = 100;
}
return (int) (Math.pow(level, x) * ((y - level * l) / d) / f);
答案 5 :(得分:0)
正如拉斐尔所说,魔术数字应该被声明为常数并且有适当的记录,
再添加一件东西来改进它,你正在三次执行相同的操作(我不确定你在第3个条件下做了什么,如果条件相同,你可以考虑四次)所以你可以声明一个提高具有许多幻数的代码的可读性的方法如下,
public int calcResult(int arg1, int arg2, int arg3)
{
return (int)(Math.pow(level, arg1) * (arg2 - level) / arg3);
}
....
int result = 0;
if (level <= 50) {
result = calcResult(3,100,50); // these can be replaced with constants.
}
else if (level <= 68 && level > 50) {
result = calcResult(3, 150, 100);
}
else if (level <= 98 && level > 68) {
result = (int) (Math.pow(level, 3) * ((1911 - 10 * level) / 3) / 500); // You can also change this accordingly.
}
else if (level < 100 && level > 98) {
result = calcResult(3, 160, 100);
}
return result;
以上代码对用户来说更具可读性,因为方法正在执行相同的操作。用常数替换幻数将会进一步改善它。
答案 6 :(得分:0)
编程不是具有硬性规则的东西。编程就是要做出权衡。为了实现良好的权衡,我们有一些商定的良好做法。对魔术数字皱眉是其中之一。
这并不意味着应该始终避免使用魔法数字。以下示例是避免幻数练习的愚蠢用法:
final int ONE = 1; // as if the value of 1 is going to change in the future
但这是可以接受的:
final int BITS_TO_SHIFT = 1;
// and further down in the code
int shifted_value = value >> BITS_TO_SHIFT;
话虽如此,让我们看看你提供的代码 是否需要幻数:
我们可以将立方体幻数移动到常数:
final int CUTOFF_1 = 50;
final int CUTOFF_2 = 68;
final int CUTOFF_3 = 98;
final int MAX = 100;
int result = 0;
if (level <= CUTOFF_1) {
result = (int) (Math.pow(level, 3) * (100 - level) / 50);
}
else if (level <= CUTOFF_2 && level > CUTOFF_1) {
result = (int) (Math.pow(level, 3) * (150 - level) / 100);
}
else if (level <= CUTOFF_3 && level > CUTOFF_2) {
result = (int) (Math.pow(level, 3) * ((1911 - 10 * level) / 3) / 500);
}
else if (level < MAX && level > CUTOFF_3) {
result = (int) (Math.pow(level, 3) * (160 - level) / 100);
}
return result;
我认为看起来更好。如果发生截止数的变化,则只需要更新常数。我相信大多数其他常量也可以通过这种方式删除。但不知道他们是什么我什么也做不了。
请注意,作为一个陌生人,我将这些神奇的数字视为任意数字的集合。创建具有描述常量目的的适当名称的常量不是更好吗?