什么是神奇数字?

为什么要避免呢?

有没有合适的情况?


当前回答

我想这是在回答你之前的问题。在编程中,魔数是一个没有解释就出现的嵌入数字常数。如果它出现在两个不同的位置,则可能导致一个实例被更改而另一个实例未更改的情况。出于这两个原因,在使用数值常数的地方之外隔离和定义数值常数是很重要的。

其他回答

在类的顶部用默认值初始化一个变量怎么样?例如:

public class SomeClass {
    private int maxRows = 15000;
    ...
    // Inside another method
    for (int i = 0; i < maxRows; i++) {
        // Do something
    }

    public void setMaxRows(int maxRows) {
        this.maxRows = maxRows;
    }

    public int getMaxRows() {
        return this.maxRows;
    }

在这种情况下,15000是一个神奇的数字(根据CheckStyles)。对我来说,设置一个默认值是可以的。我不想做的事情是:

private static final int DEFAULT_MAX_ROWS = 15000;
private int maxRows = DEFAULT_MAX_ROWS;

这会让它更难读吗?在安装CheckStyles之前,我从未考虑过这一点。

@eed3si9n:我甚至认为“1”是一个神奇的数字。: -)

与神奇数字相关的一个原则是,代码处理的每个事实都应该声明一次。如果您在代码中使用神奇的数字(例如@marcio给出的密码长度示例),那么您很容易复制该事实,当您对事实的理解发生变化时,您就会遇到维护问题。

我总是以不同的方式使用术语“魔数”,作为存储在数据结构中的模糊值,可以作为快速有效性检查进行验证。例如,gzip文件的前三个字节包含0x1f8b08, Java类文件以0xcafebabe开头,等等。

您经常看到在文件格式中嵌入了神奇的数字,因为文件可以相当混乱地四处发送,并丢失关于它们如何创建的任何元数据。然而,魔法数字有时也用于内存中的数据结构,如ioctl()调用。

在处理文件或数据结构之前快速检查这个神奇的数字,可以尽早发现错误,而不是为了宣布输入完全是胡编乱作而进行可能很长的处理。

Magic Number是一个硬编码的值,它可能在以后的阶段更改,但因此很难更新。

例如,假设您有一个页面,在“您的订单”概览页面中显示最近50个订单。50在这里是一个神奇的数字,因为它不是通过标准或惯例设置的,它是您根据规范中概述的原因虚构的数字。

现在,你要做的是你在不同的地方有50个-你的SQL脚本(SELECT TOP 50 * FROM orders),你的网站(你的最后50个订单),你的订单登录(for (i = 0;I < 50;i++))和可能的许多其他地方。

那么,如果有人决定把50岁改成25岁,会发生什么呢?还是75年?还是153年?现在你必须在所有的地方替换50,你很可能会错过它。Find/Replace可能不起作用,因为50可能用于其他事情,盲目地将50替换为25可能会产生一些其他不良副作用(即你的Session)。Timeout = 50呼叫,也设置为25,用户开始报告太频繁的超时)。

此外,代码可能很难理解,即。"if a < 50那么bla"——如果你在一个复杂的函数中遇到这种情况,其他不熟悉代码的开发人员可能会问自己"WTF是50?? "

这就是为什么最好在1个地方有这样模糊和任意的数字-“const int NumOrdersToDisplay = 50”,因为这使代码更具可读性(“如果< NumOrdersToDisplay”,这也意味着你只需要在1个定义良好的地方更改它。

适用Magic Numbers的地方是通过标准定义的所有内容,即SmtpClient。DefaultPort = 25或TCPPacketSize =任何(不确定是否标准化)。此外,只在一个函数中定义的所有内容都可能是可接受的,但这取决于上下文。

在编程中,“神奇的数字”是一个值,它应该被赋予一个符号名称,但却被作为文字插入到代码中,通常在多个地方。

它不好的原因与SPOT (Single Point of Truth)好的原因是一样的:如果以后想更改这个常量,就必须遍历代码以找到每个实例。这也很糟糕,因为其他程序员可能不清楚这个数字代表什么,因此出现了“魔术”。

人们有时会进一步使用神奇数字消除,将这些常量移到单独的文件中作为配置。这有时是有帮助的,但也会带来更多的复杂性。