-1是一个神奇的数字?反模式?代码味道?当局的报价和指南

pol*_*nts 12 java magic-numbers

可能重复:
持续滥用?

我已经看到-1在各种API中使用,最常见的是搜索具有从零开始的索引的"集合"时,通常用于指示"未找到"索引.这"有效",因为-1从来不是一个合法的索引.似乎任何负数都应该有效,但我认为-1几乎总是使用某种(不成文的?)约定.

我想至少暂时将范围限制为Java.我的问题是:

  • 关于使用-1像这样的"特殊"返回值,Sun的官方文字是什么?
  • 关于这个问题有哪些引用,例如James Gosling,Josh Bloch,甚至是Java以外的其他权威人士?
  • 过去有关这个问题的一些值得注意的讨论是什么?

mdm*_*dma 11

这是一种常见的语言,其中的类型不包括范围检查."越界"值用于表示几种情况之一.这里,返回值表示两件事:1)是找到的字符,2)它在哪里找到.使用-1 for not found和非负索引found将这两者简洁地编码为一个值,以及not-found不需要返回索引的事实.

在具有严格范围检查的语言中,例如Ada或Pascal,该方法可以实现为(伪代码)

   bool indexOf(c:char, position:out Positive);
Run Code Online (Sandbox Code Playgroud)

Positive 是int的子类型,但仅限于非负值.

这将找到/未找到的标志与位置分开.该位置作为输出参数提供 - 基本上是另一个返回值.它也可以是一个输入输出参数,从给定位置开始搜索.这里不允许使用-1表示not-found,因为它违反了Positive类型的范围检查.

java中的替代方案是:

  • 抛出异常:这不是一个好的选择,因为找不到一个字符并不是一个例外情况.
  • 将结果分成几种方法,例如boolean indexOf(char c); int lastFoundIndex();.这意味着对象必须保持状态,这在并发程序中不起作用,除非状态存储在线程本地存储中,或者使用同步 - 所有相当大的开销.
  • 返回位置并分别找到标志:如boolean indexOf(char c, Position pos).这里,创建位置对象可能被视为不必要的开销.
  • 创建一个多值返回类型

class FindIndex {
   boolean found;
   int position;
}

FindIndex indexOf(char c);
Run Code Online (Sandbox Code Playgroud)

虽然它明确地区分了返回值,但它会受到对象创建开销的影响.其中一些可以通过传递FindIndex作为参数来减轻,例如

FindIndex indexOf(char c, FindIndex start);
Run Code Online (Sandbox Code Playgroud)

顺便提一下,多个返回值将成为java(oak)的一部分,但是在1.0之前被削减以缩短发布时间.詹姆斯戈斯林他希望他们被包括在内.它仍然是一个希望的功能.

我的看法是使用魔术值是在单个返回值中编码多值结果(标志和值)的实用方法,而不需要过多的对象创建开销.

但是,如果使用魔术值,如果它们在相关的api调用中保持一致,则使用它会更好.例如,

   // get everything after the first c
   int index = str.indexOf('c');
   String afterC = str.substring(index);
Run Code Online (Sandbox Code Playgroud)

Java在这里不足,因为在调用中使用-1 substring会导致IndeOutOfBoundsException.相反,如果将负值视为在字符串末尾开始,则在使用-1调用时,子字符串返回""可能更加一致.对错误条件的魔术值的批评者说,可以忽略返回值(或假设为正数).以有用的方式处理这些魔术值的一致api将减少检查-1并允许更清晰的代码的需要.