Java 1是一个神奇的数字吗?反模式?代码气味?当局的引文和指南
可能重复:Java 1是一个神奇的数字吗?反模式?代码气味?当局的引文和指南,java,magic-numbers,Java,Magic Numbers,可能重复: 我在各种API中看到了-1,最常见的是在搜索具有零基索引的“集合”时,通常表示“未找到”索引。这“有效”,因为-1从来都不是一个合法的索引。似乎任何负数都应该起作用,但我认为几乎总是使用-1,作为某种(不成文的)惯例 我想将范围限制在Java,至少现在是这样。我的问题是: Sun关于使用-1作为这样的“特殊”返回值的官方说法是什么 关于这个问题,有哪些引用,例如James Gosling、Josh Bloch,甚至Java以外的其他权威人士 过去关于这个问题有哪些值得注意的讨论
我在各种API中看到了
-1
,最常见的是在搜索具有零基索引的“集合”时,通常表示“未找到”索引。这“有效”,因为-1
从来都不是一个合法的索引。似乎任何负数都应该起作用,但我认为几乎总是使用-1
,作为某种(不成文的)惯例
我想将范围限制在Java,至少现在是这样。我的问题是:
- Sun关于使用
作为这样的“特殊”返回值的官方说法是什么-1
- 关于这个问题,有哪些引用,例如James Gosling、Josh Bloch,甚至Java以外的其他权威人士
- 过去关于这个问题有哪些值得注意的讨论
当找不到索引时,Java和JavaScript都使用
-1
。由于索引总是0-n
,因此这似乎是一个非常明显的选择
//JavaScript
var url = 'example.com/foo?bar&admin=true';
if(url.indexOf('&admin') != -1){
alert('we likely have an insecure app!');
}
我发现这种方法(我在扩展数组类型元素时使用了.indexOf()
方法)非常正常
另一方面,您可以尝试使用PHP方法,例如,但由于存在多个返回类型(未找到时返回FALSE),这会让人感到困惑。最好为代码中的所有常量值定义一个最终的类变量。
但一般接受使用0,1,-1“(空字符串),而不使用显式声明。这是从C继承的,其中只能返回单个原语值。在java中,还可以返回单个对象 因此,对于新代码,返回一个basetype对象,其子类型指示instaceof要使用的问题,或者抛出一个“not Found”异常
对于现有的特殊值,相应地在您的代码名中使-1成为常量-未找到-因此读者无需检查javadocs即可说出其含义 与
null
相同的做法适用于-1
。它被讨论了很多次
e、 g.之所以使用它,是因为它是在基于0的数组中遇到的第一个无效值。正如您所知,并非所有类型都可以包含null或nothing,因此需要“something”来表示nothing
我想说它不是官方的,它只是成为了惯例(不成文),因为它非常适合这种情况。就我个人而言,我不认为这是一个问题。API设计也取决于作者,但是。在类型不包括范围检查的语言中,这是一个常见的习惯用法。“越界”值用于指示多个条件之一。这里,返回值表示两件事:1)字符是在哪里找到的,2)在哪里找到的。 使用-1表示
未找到
,使用非负索引表示已找到
可将这两个值简洁地编码为一个值,未找到
这一事实不需要返回索引
在具有严格范围检查的语言中,如Ada或Pascal,该方法可以实现为(伪代码)
Positive
是int的一个子类型,但仅限于非负值
这将发现/未发现标志与位置分开。该位置作为输出参数提供-本质上是另一个返回值。它也可以是一个in-out参数,用于从给定位置开始搜索。此处不允许使用-1表示找不到,因为它违反了正数类型的范围检查
java中的备选方案有:
- 抛出异常:这不是一个好的选择,因为找不到角色不是一个异常情况
- 将结果拆分为几种方法,例如
boolean indexOf(char c);int lastFoundIndex()代码>。这意味着对象必须保持状态,而状态在并发程序中不起作用,除非状态存储在线程本地存储中,或者使用同步——所有这些都会带来相当大的开销
- 分别返回位置和查找标志:例如
。这里,创建位置对象可能被视为不必要的开销李>布尔索引of(char c,position pos)
- 创建多值返回类型
class FindIndex {
boolean found;
int position;
}
FindIndex indexOf(char c);
尽管它清楚地分隔了返回值,但它会承受对象创建开销。通过将FindIndex
作为参数传递,可以缓解其中的一些问题,例如:
FindIndex indexOf(char c, FindIndex start);
顺便说一句,多个返回值将成为java(oak)的一部分,但在1.0之前就被删除了,以缩短发布时间。詹姆斯·戈斯林,他希望他们也包括在内。这仍然是一个问题
我的观点是,使用魔术值是在单个返回值中编码多值结果(一个标志和一个值)的一种实用方法,而不需要过多的对象创建开销
但是,如果使用魔法值,如果它们在相关api调用中保持一致,那么使用魔法值会更好。比如说,
// get everything after the first c
int index = str.indexOf('c');
String afterC = str.substring(index);
Java在这方面存在不足,因为在调用
子字符串
时使用-1将导致IndeOutOfBoundsException
。相反,如果将负值视为从字符串末尾开始,则使用-1调用substring时返回“”可能更一致。错误条件下神奇值的批评者说返回值可以忽略(或假定为正)。以有用的方式处理这些神奇值的一致api将减少检查-1的需要,并允许更干净的代码。据我所知,这些值称为sentinel值,尽管大多数常见的定义与此场景略有不同
Java等语言选择不支持按引用传递(我认为这是一个好主意),因此,虽然各个参数的值是可变的,但传递给函数的变量不受影响。因此,y
// get everything after the first c
int index = str.indexOf('c');
String afterC = str.substring(index);
someCollection.objectAtIndex(someCollection.indexOf(someObject)) == someObject
int i = someString.indexOf("substring");
if (i>=0) {
// do stuff with found index
} else {
// handle not found case
}