为什么String.indexOf不使用exception但在找不到子字符串时返回-1?
为什么String.indexOf不使用exception但在找不到子字符串时返回-1?
这个问题的目的是:当我们开始自定义exception时。
我相信避免需要返回特殊错误代码是正确的设计路径。
你怎么看?
根据经验,如果方法的目的是检查某些东西,那么缺少某些东西不应该是一个例外。 如果方法假设某些事情是真的,那么缺少那个东西将是一个例外。 因此“File.exists()”不会抛出FileNotFoundException,但“File.open()”会抛出。
例外是针对特殊情况,当字符串不包含字母时,这几乎不例外,除非您在某些极端情况下使用它。 如果这就是你在做什么,你总是可以选择抛出自己的exception。
最后我听到的是……
“当你的方法无法做到它所承诺的时候,你会抛出exception” – Jeff Richter CVC第二版
- IndexOf()承诺返回第一次出现的char / string的索引。 如果由于某种原因无法完成工作,它会引发exception。 它完成了它的工作,但没有找到字符串,因此返回-1来传达未找到的结果。
- File.Open()将为不存在的文件路径抛出FileNotException,因为它无法执行它所承诺的内容。即打开指定的文件。
返回-1几乎和抛出exception一样可怕。 正确的方法是使用选项类型,如果语言更好地支持它。 在有结果的正常情况下,将结果包装在对象中并返回该结果。 否则,您将返回表示“未结果”情况的对象。
在通话网站,你必须检查它是哪一个; 你不能只使用返回值因为它们的超类型,它们必须通过模式匹配进行检查。
在伪语法中:
class Option[a] = Some[a] | None,
其中a是generics类型参数,Some表示带有值的结果,None表示没有值的非结果。
在indexOf的情况下你会有:
Option[Integer] indexOf(char c) = { if(found) return Some(index) else return None }
你用这种方式:
result = "uncle".indexOf('c') result match { Some(i) => System.out.println("index was: " + i); None => System.out.println("no value"); }
如果你从匹配中省略了Some或None(这是一种通用的开关),编译器会给你一个警告。
处理检查-1比处理exception要容易得多。
另外,因为例外在性能方面很昂贵
除了一般反对exception的参数之外,我还要补充一点,-1可以是indexOf和lastIndexOf的有用结果,而不仅仅是一个特殊值。 例如,要从可能包含或不包含路径的字符串中解析文件名:
String filename = arg.substring(arg.lastIndexOf('/') + 1);
虽然可能是一个人为的例子,但除了例外情况,这会更麻烦。
这里有很多好的答案。 这是一个设计问题,其中实用主义优先于遵循“规则”。 在这种情况下,存在一些相互矛盾的“规则”:
- 避免使用特殊值作为返回数据(不是自我记录,要求开发人员以与其他代码不同的方式处理特殊值)
与
- 在代码的例行执行期间,只有在出现意外情况时才会抛出exception
我同意这个设计决定。 但是,如果不这样做,则可以在检查索引之前始终编写自己的代码以检查字符串是否存在。 不要成为你的语言的囚犯,屈服于你的意志。 语言意味着折磨!
我认为当出现意外情况时,必须抛出exception。 也就是说,String中找不到的子字符串不是意外的,可能会发生,这是一个合理的结果。
我同意你应该尽量避免返回错误代码,但在这种情况下,我们只有两个选择,找到字符串或找不到字符串。
直到Java的string.indexOf
的作者告诉我们实际的历史……
让我们假设我们必须从头开始设计它,这个问题有一些明显的设计约束:
-
indexOf
必须返回一个数值,以便在找到匹配项时知道它在哪里 - 有效索引保证总是整数
- 数组(和字符串)索引在Java中从零开始
- Java是强类型的
- 整数数字类型在Java中签名
给定这些基本约束,函数返回类型的一些可能选择是整数(理想情况下是足以表示最大可能字符串中的最后一个索引的类型),OR … Object
(并且可能返回null以指示未找到) 。 但实际上返回Object
既不高效也不方便用户,因为需要检查其有效性并在使用之前进行铸造 – 因此它不是真正可行的选择!
那么我们来看一个整数。 如果找不到,我们是否要抛出exception? 抛出exception有其自身的多个问题 – 创建exception对象并跳转到exception处理程序可能效率很低,并且在indexOf
调用周围编写try / catch块也不好玩!
所以我们说我们已经缩小了它:它必须返回一个(带符号)整数类型,而不是抛出exception。 现在应返回哪个整数值表示未找到?
为了允许在尽可能大的字符串中进行搜索,我们应该保留所有正整数以用于成功找到的含义。 相反,代表“找到”索引不需要任何负数,因此所有可能都可用作表示“未找到”的返回码。
如果我们可以选择任何负数,代表未找到,或只是说“所有负面回报值意味着没有找到”它就能完成这项工作……但它会是最好的设计吗?
使用-1而不是其他负数的原因是什么? 我最喜欢的原因是’-1很容易让每个人都记住,你可以对它进行完全相同的测试’。 (而不是被迫使用不等式并考虑一个一个一个的问题,比如你是想要低于或低于或等于,以及与之比较的值,零或负值)
我有时也很欣赏克里斯的理由(释义)’它与substring(foundIndex + 1)
‘很好地配合。