views:

598

answers:

9

Why String.indexOf do not use exception but return -1 when substring not found?

The purpose of this question is: when we start custom exception.

I believe avoid the need to return special error code is right design path.

What's your opinion?

+16  A: 

exceptions are for exceptional cases, when a string does not contain a letter, that's hardly exceptional, unless you are using it for some extreme case. If that's what you are doing, you can always choose to throw your own exception.

yx
+1 for "exceptions are for exceptional cases". One might ask, "why doesn't File.exists() throw a FileNotFoundException instead of returning false"? Similar concept; you call both methods in the knowledge that it's quite likely for the condition to be negative.
Rob
Perhaps it is considered quite normal for a file to not exist, otherwise why have a method to test for it rather than just assume the file you ask for is going to be there.
Peter Lawrey
+3  A: 

It's a lot easier to deal with checking for a -1 than catching an exception.

Gromer
+3  A: 

Also because exceptions are expensive in terms of performance

+1  A: 

I think that one has to throw an exception when something unexpected happens. That said, a substring not found in a String is not that unexpected, can happen, it is a reasonable result.

I agree with you that one should try to avoid returning error codes, but in this case we have only two choices, string found or string not found.

Alberto Zaccagni
+12  A: 

Last I heard on that was...

'You throw an exception when your method is unable to do what it promises to' - Jeff Richter CVC 2nd ed

  • IndexOf() promises you to return the index of the first occurrence of a char/string. It would have thrown an exception if it was unable to do its job for some reason. It did its job but didn't find the string and hence returns -1 to convey the not-found result.
  • File.Open() will throw a FileNotException for a non-existing filepath since it is unable to do what it promises .. i.e. open the specified file.
Gishu
Add Paul's comments here.As a rule of thumb, if the purpose of a method is to check for something, then the lack of that something shouldn't be an exception. If the method is assuming that something is true, then the absence of that something would be an exception. Thus "File.exists()" doesn't throw a FileNotFoundException, but "File.open()" does.
ariso
+1 to Paul. It follows from the quote above, Any possible results/return values in case the method succeeds should *not* be in the form of an exception. The method should only throw an exception to indicate that it was unable to perform its duty/reason for being.
Gishu
The fault is on the String's side (because it doesn't have the String you search), not on the method side.
Valentin Rocher
+10  A: 

As a rule of thumb, if the purpose of a method is to check for something, then the lack of that something shouldn't be an exception. If the method is assuming that something is true, then the absence of that something would be an exception. Thus "File.exists()" doesn't throw a FileNotFoundException, but "File.open()" does.

Paul Tomblin
I think Paul have the right answer.because file.exists() do not throw exceptions.
ariso
+1  A: 

Aside from the arguments against exceptions in general, I would add that -1 can be a useful result from indexOf and lastIndexOf, not just a special value. For instance, to parse the filename from a string that may or may not contain a path:

String filename = arg.substring(arg.lastIndexOf('/') + 1);

While perhaps a contrived example, this would be a bit more cumbersome with exceptions.

Chris Thornhill
A a matter of fact, I'd consider this a hack. It's a beautiful one, but still, it's not clear the developer coming after you would understand. At least use a comment...
sleske
@Sleske A hack? A useful return value is not a hack. A comment? What would you like to add that is not already stated in the JavaDoc of these (simple) functions?
eljenso
@eljenso - I agree that 'hack' might be a little strong. But looking at the code does NOT make it intentions clear. Another programmer could very easily look at this is and think the author 'missed' the no '/' case.Clever and maintainable don't always go hand-in-hand.
kenj0418
+2  A: 

Lots of good answers here. This is a design issue where pragmatism has taken precedence over following "rules". In this case, there are some conflicting "rules":

  • avoid using special values as return data (not self-documenting, requires developer to handle special value in a distinct way from other code)

vs.

  • don't throw exceptions during routine execution of code, only when something unexpected happens

I agree with this design decision. If you do not, however, you can always write your own code to check for the existence of a string before checking its index. Do not be a prisoner of your language, bend it to your will. Languages are meant to be tortured!

RedFilter
+3  A: 

returning -1 is almost as horrible as throwing an exception. The correct way would be to use option type if language just supported it better. In normal situation where there is result, you wrap the result in object and return that. Otherwise you return an object representing the "not result" situation.

In call site you have to check which one was it; you can't just use the return value because of their super type, they have to be inspected via pattern matching.

In pseudo syntax:

class Option[a] = Some[a] | None,

where a is generic type parameter, Some represents a result with value and None non-result without value.

in indexOf case you would have:

Option[Integer] indexOf(char c) = {
   if(found) return Some(index)
   else return None
}

and you use that this way:

result = "uncle".indexOf('c')
result match {
  Some(i) => System.out.println("index was: " + i);
  None => System.out.println("no value");
}

If you omitted either Some or None from matching (which is kinda generalized switch), compiler would give you a warning.

egaga
Java is not Haskell. And -1 can be a *useful* return value when manipulating Strings. So returning -1 is far from horrible in Java, and certainly not as horrible as throwing an exception.
eljenso
Exception won't go unnoticed, but it's possible that your program logic will silently go awry, when you're dealing with a number. Plus -1 doesn't have any readability value. Just an arbitrary value.
egaga
I agree. throw exception will make code more complete and not easy to understanding....
ariso
Why do you say that -1 is "just an arbitrary value"?
eljenso
An Option type is provided by Functional Java: http://functionaljava.org. Also provided is a LazyString type whose indexOf method returns an Option<Integer>.
Apocalisp
Eljenso, because there's no meaning behind it, it could as well as be -3424. A yet another magic number that one have to remember.
egaga
@eljenso From a practical point of view, I don't agree. -3424 is a lot harder to remember. Note that the indexes into a String are zero-based, so if you return an integer to represent something "outside" the range of a String of length 0<=n, -1 seems a hell of a lot better than -3424. Would it be ok for you if they index characters in a String starting from -3424? After all 0 (or 1) are just arbitrary numbers as well...
eljenso
Well it's true -1 is easier to remember (nearest invalid integer with smallest digits). But anyway, it's still an integer which really doesn't make it stand out from the valid indexes.
egaga