这是类型不包含范围检查的语言中的常见习惯用法。 “越界”值用于指示几个条件之一。在这里,返回值指示两件事:1)是找到的字符,2)在哪里找到的。
使用 -1 来表示not found
和一个非负索引found
简洁地将这两者编码为一个值,并且事实是not-found
不需要返回索引。
在具有严格范围检查的语言中,例如 Ada 或 Pascal,该方法可能会实现为(伪代码)
bool indexOf(c:char, position:out Positive);
Positive
是 int 的子类型,但仅限于非负值。
这将找到/未找到标志与位置分开。该位置作为输出参数提供 - 本质上是另一个返回值。它也可以是输入输出参数,从给定位置开始搜索。此处不允许使用 -1 来指示未找到,因为它违反了对 Positive 类型的范围检查。
java 中的替代方案是:
- 抛出异常:这在这里不是一个好的选择,因为找不到字符并不是异常情况。
- 将结果分成几种方法,例如
boolean indexOf(char c); int lastFoundIndex();
。这意味着对象必须保留状态,这在并发程序中不起作用,除非状态存储在线程本地存储中,或者使用同步 - 所有这些都会产生相当大的开销。
- 分别返回位置和找到的标志:如
boolean indexOf(char c, Position pos)
。在这里,创建位置对象可能被视为不必要的开销。
- 创建多值返回类型
such as
class FindIndex {
boolean found;
int position;
}
FindIndex indexOf(char c);
尽管它清楚地分隔了返回值,但它会产生对象创建开销。通过通过FindIndex
作为参数,例如
FindIndex indexOf(char c, FindIndex start);
顺便说一句,多个返回值本来是 java (oak) 的一部分,但在 1.0 之前被取消,以缩短发布时间。詹姆斯·高斯林says http://www.gotw.ca/publications/c_family_interview.htm他希望他们也被包括在内。它仍然是一个想要的功能 https://bugs.java.com/bugdatabase/view_bug?bug_id=4222792.
我的看法是,使用魔法值是在单个返回值中编码多值结果(标志和值)的实用方法,而不需要过多的对象创建开销。
但是,如果使用魔法值,并且它们在相关 api 调用之间保持一致,那么使用起来会更好。例如,
// get everything after the first c
int index = str.indexOf('c');
String afterC = str.substring(index);
Java 在这方面有所不足,因为在调用中使用了 -1substring
将导致IndeOutOfBoundsException
。相反,如果认为负值从字符串末尾开始,则在使用 -1 调用时,子字符串返回“”可能会更加一致。对错误条件的魔法值的批评者表示,返回值可以被忽略(或假设为正)。以有用的方式处理这些魔法值的一致 api 将减少检查 -1 的需要并允许更清晰的代码。