这是类型不包括范围检查的语言中的常见习语。“超出范围”值用于指示若干条件之一。在这里,返回值表示两件事:1) 是找到的字符,以及 2) 在哪里找到的。使用 -1not 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)
. 在这里,创建位置对象可能被视为不必要的开销。
- 创建多值返回类型
如
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 在这方面做得不够,因为在调用中使用 -1substring
会导致IndeOutOfBoundsException
. 相反,如果认为负值从字符串的末尾开始,则在使用 -1 调用时,子字符串返回“”可能会更加一致。错误条件的魔法值的批评者说返回值可以被忽略(或假设为正)。以一种有用的方式处理这些魔法值的一致 api 将减少检查 -1 的需要并允许更清晰的代码。