Related
In the JLS8, chapter "Exceptions" (here), I saw that:
Explicit use of throw statements provides an alternative to the
old-fashioned style of handling error conditions by returning funny
values, such as the integer value -1 where a negative value would not
normally be expected. Experience shows that too often such funny
values are ignored or not checked for by callers, leading to programs
that are not robust, exhibit undesirable behavior, or both.
Actually, I'm not clear about 2 issues following:
(1) "such as the integer value -1 where a negative value would not normally be expected", why "a negative value would not normally be expected"? Follow my knowledge, we often use return value "-1" for an error, abnormal event,... or something "not good".
(2) "Experience shows that too often such funny values are ignored or not checked for by callers, leading to programs that are not robust, exhibit undesirable behavior, or both.". What "funny values are ignored or not checked for by callers, leading to programs that are not robust, exhibit undesirable behavior, or both" means? I don't understant this issue...Please help me to clarify and (if yes) give me an example to demonstrate
Thank you so much
A common example is: people not checking the contents of a string, but blindly calling indexOf() - and not taking into account that the "thing searched for" isn't in that string, so the returned result is -1.
At least when using checked exception the programmer must do something about a potential exception thrown from some code that his code is using. For return values, you can completely ignore them - just a bit easier therefore.
On the other hand, many people argue that the idea of checked exception didn't live up to its promise - and are therefore advocating the usage of unchecked exceptions. Or alternatively, as companies such as google propose: the usage of more sophisticated "return value classes".
Long story short:
by the nature of the language exceptions should be seen as the primary mean to communicate severe exceptional conditions
but that doesn't mean that using numeric return codes is not possible or completely discouraged.
Please help me to clarify and (if yes) give me an example to demonstrate:
For example Class.getResourceAsStream(String) returns null if it cannot find the resource, rather than throwing an exception. This is clearly documented in the javadocs.
However, lots of people don't read the documentation, and don't check the result of a getResourceAsStream call. As a result, when the resource is missing, they use the null and get an unexpected NullPointerException.
Another common example is ServletRequest.getParameter(String).
If you analysed the NPE Q's on StackOverflow, you would find that a significant number of them are caused by people not checking the results of the above two methods. (If you don't believe me, the raw questions are available for you to analyse!)
Why using error code (such as -1) is not efficient than using exception?
The text you quoted doesn't say that. And it is probably not true. In fact, the using an error code is (classically) more efficient in many cases. However, with recent JIT compiler improvements, the overheads of exceptions and exception handling have been significantly reduced for typical use-cases.
Summary:
People are lazy. But you knew that!
People are careless. But you knew that!
APIs that require people to check returned values are less robust than those that throw (checked) exceptions ... because people write code that doesn't check return codes. Why? Because people are lazy, careless or both!
Admittedly, there are pragmatic reasons not to throw exceptions. However it is a trade-off of robustness vs efficiency vs forcing the programmer to deal with checked exceptions.
The text you quoted is not trying to tell you use exceptions always. Rather it is explaining the reasons that exceptions are part of the Java language.
You may disagree, but ... frankly ... it is not a topic that is worth debating. Exceptions (checked / unchecked, etc) are so hard-baked into the Java language that it would be impossible to change.
(1) "such as the integer value -1 where a negative value would not normally be expected", why "a negative value would not normally be expected"?
It is a proven fact (see below) that people don't always check return values.
Follow my knowledge, we often use return value "-1" for an error, abnormal event,... or something "not good".
True. And exceptions provide an alternative.
What "funny values are ignored or not checked for by callers
'Funny values' such as -1. There are examples posted here every hour of every day.
leading to programs that are not robust, exhibit undesirable behavior, or both" means?
It means that programs that ignore 'funny values' aren't robust or exhibit undesirable behaviour ... and give rise to trivial questions on this site.
I don't understand this issue...Please help me to clarify and (if yes) give me an example to demonstrate.
Try this search for hundreds of examples.
When a method return an int, the caller have to check if it is an error code. But if here is no expected range of returned value, how could you specify an error signal value?
Let us say what "error code" should a parseInt method return?
And if the caller "forgets" to check the returned value, the error could go unnoticed.
However if an exception is declared, the caller must check and handle it, by catching it or declaring i in throws...
I am writing code to find and intersection of 2 lines.
When slopes of the lines are equal they dont intersect. But on the other hand an input with slopes of equal value is completely valid.
public static Point calculateIntersection(Line line1, Line line2) {
if (line1 == null || line2 == null) {
throw new NullPointerException(" some message ");
}
if (line1.getConstant() == line2.getConstant()) {
return new Point(0, line1.getConstant());
}
if (line1.getSlope() == line2.getSlope()) {
throw new IllegalArgumentException("slopes are same, the lines do not intersect.");
}
int x = (line2.getConstant() - line1.getConstant()) / (line1.getSlope() - line2.getSlope());
int y = line1.getSlope() * x + line1.getConstant();
return new Point(x, y);
}
The question is throwing illegal argument exception the right thing to do ?
Since input is valid, it does not completely convince me.
Is custom exception the right thing to do ?
Sounds like a good choice but an additional opinion would help.
Thanks
The question is is throwing illegal argument exception the right thing to do?
There is no single "right thing to do". It depends on how you want / need to "frame" this condition; i.e. is it a bug, a user input error, or something that the program is supposed to be able to deal with?
If the case of two lines not intersecting is unequivocally a "bug", then IllegalArgumentException is fine. This is what the exception is designed for. (Note that it is an unchecked exception, so the expectation is that it won't be caught / recovered from.)
If this is a case that you expect the program to be able to recover from by itself, then a custom exception is the best idea. That way, you reduce the possibility of your code getting confused by (say) a library method throwing (say) an IllegalArgumentException ... than means something other than "two lines intersected".
If this case is something that you expect to report to the end user as part of input validation, then a generic "validation error" exception might be more appropriate than a specific custom exception. However, this method doesn't look like it is designed to be used (solely) for user input validation.
In some contexts, it may be better to not throw an exception at all, but (IMO) this is not one of those contexts.
The alternatives to throwing an exception are returning null or returning a Point value that means "no such point" to the calling code. The problems with these alternatives are:
If you return null the application has to deal with the null case ... or there will be NPEs.
There is no natural Point instance that could be used to mean "not a point"1.
This is not to say that you couldn't make these alternatives work. It is just that in this context, it will probably be more work to do that, and probably there won't be a tangible pay-off.
1 - I am assuming Point is java.awt.Point or similar. Obviously you could define and use a custom Point class which provides a "no such point" instance. But it will come at a cost. And you will need to deal with the case where code accidentally uses the "no such point" instance in some computation. And you are probably back where you started; i.e. throwing an exception!
This almost certainly should not throw an exception, because it makes perfect sense to invoke a method like this with any two Line values. You have already appropriately handled null values.
You have also, very reasonably, defined the behavior of your class in one of the ill-defined input situations, namely two coincident "constant" (horizontal) lines, where you return the point at x=0 on that line. You ought to similarly select return values for the other cases of ill-defined inputs: coinciding vertical lines, coinciding lines that are neither horizontal nor vertical, and non-coinciding parallel lines.
In my opinion, the most natural result for the last case - non-coinciding parallel lines - would be null, reflecting the fact that there is no point of intersection.
It would then be up to the client to decide whether a null intersection warrants an exception, an error message, or whatever. E.g. an interactive shell prompting the user for lines to intersect would probably print an error message and ask the user to try again. Some more complicated calculation, e.g. a linear optimizer trying to define boundaries for its search, might want to throw IllegalArgumentException if the constraints giving rise to the parallel lines contradict each other.
Of course, the return values in all these cases (coincident lines or non-coincident parallel lines) should be precisely documented in the method's javadoc.
I'd say you do the right thing: you catch the condition early. It is either that or people will complain that "your program is buggy, look at this input data, division by 0".
Given that there will be no such error in 99+% of situations, this is an exceptional condition and doesn't grant declaring a checked exception, so an unchecked exception looks indeed like the right choice.
Now, as to whether IllegalArgumentException is the "good one", it is at least the closest exception describing this case... You can, if you feel you have a better name, always create your own one inheriting RuntimeException.
IF, on the other hand, this situation is not that infrequent, then maybe the logic to reach that function should be reviewed so as to never hit this condition in the first place.
As #Andy-Lowry and #KamikazeCZ say, this should not be an exception.
This method should not concern itself with whether the client expects lines to always intersect or not; it should only bother with finding the intersection of two lines -- something which inherently might not happen.
If the caller gets back a result indicating no-intersection, then THAT code can decide whether it's invalid-input because the end-user was duly warned, or something they can handle (perhaps by re-prompting), or throw a customized exception.
So, back to what should this method return? Some sort of sentinel value, the same way that indexOf returns -1 in the collections library. Returning null is a reasonable sentinel. In Java 8, you can return an Optional<Point>, to help remind the caller that there might not be a proper Point.
You have an additional problem, too: what somebody asks for the intersection of a line with itself? (Mathematically, the intersection of two lines is either 0 point, 1 point, or infinitely many points.) You might need to be able to return two sentinel values, which is more involved, in Java. This method could weasel out of the situation this time, by saying "in the case of multiple answers, this method may return any of them", or (what I'd probably do) "...returns the Point nearest the origin".
Btw, this thinking largely follows from a unit-test mindset: start by defining the correct answer should be for a variety of corner-case inputs, before launching into code and kinda committing yourself to a certain return-type etc.
Finally: when comparing the results of getSlope() using ==, beware floating-point roundoff errors. It might be the best thing to do here, but it's still problematic. The way you assume (or round) the intersection to ints, though, suggests you might have very special constraints/assumptions going on in your problem.
Keep in mind that a more generic version of this question was closed as primarily opinion-based.
If it were me, I would return null. In most cases you should not use exception handling as a form of flow control. Returning null would help avoid that for any code consuming your method.
Related Discussions:
Dont Use Exceptions For Flow Control
Should a retrieval method return 'null' or throw an exception when it can't produce the return value? [closed]
Are exceptions as control flow considered a serious antipattern? If so, Why?
Arguments for or against using Try/Catch as logical operators [closed]
Exceptions should be used to catch errors in program flow ("what happens inside") , not for input validation. I wouldn't throw an exception at all.
Think about it, this is not what "exception" means as it is completely normal for the user to input two lines with equal slopes.
Given the code:
public static int sum(String a, String b) /* throws? WHAT? */ {
int x = Integer.parseInt(a); // throws NumberFormatException
int y = Integer.parseInt(b); // throws NumberFormatException
return x + y;
}
Could you tell if it's good Java or not? What I'm talking about is, NumberFormatException is an unchecked exception. You don't have to specify it as part of sum() signature. Moreover, as far as I understand, the idea of unchecked exceptions is just to signal that program's implementation is incorrect, and even more, catching unchecked exceptions is a bad idea, since it's like fixing bad program at runtime.
Would somebody please clarify whether:
I should specify NumberFormatException as a part of method's signature.
I should define my own checked exception (BadDataException), handle NumberFormatException inside the method and re-throw it as BadDataException.
I should define my own checked exception (BadDataException), validate both strings some way like regular expressions and throw my BadDataException if it doesn't match.
Your idea?
Update:
Imagine, it's not an open-source framework, that you should use for some reason. You look at method's signature and think - "OK, it never throws". Then, some day, you got an exception. Is it normal?
Update 2:
There are some comments saying my sum(String, String) is a bad design. I do absolutely agree, but for those who believe that original problem would just never appear if we had good design, here's an extra question:
The problem definition is like this: you have a data source where numbers are stored as Strings. This source may be XML file, web page, desktop window with 2 edit boxes, whatever.
Your goal is to implement the logic that takes these 2 Strings, converts them to ints and displays message box saying "the sum is xxx".
No matter what's the approach you use to design/implement this, you'll have these 2 points of inner functionality:
A place where you convert String to int
A place where you add 2 ints
The primary question of my original post is:
Integer.parseInt() expects correct string to be passed. Whenever you pass a bad string, it means that your program is incorrect (not "your user is an idiot"). You need to implement the piece of code where on one hand you have Integer.parseInt() with MUST semantics and on the other hand you need to be OK with the cases when input is incorrect - SHOULD semantics.
So, briefly: how do I implement SHOULD semantics if I only have MUST libraries.
In my opinion it would be preferable to handle exception logic as far up as possible. Hence I would prefer the signature
public static int sum(int a, int b);
With your method signature I would not change anything. Either you are
Programmatically using incorrect values, where you instead could validate your producer algorithm
or sending values from e.g., user input, in which case that module should perform the validation
Hence, exception handling in this case becomes a documentation issue.
This is a good question. I wish more people would think about such things.
IMHO, throwing unchecked exceptions is acceptable if you've been passed rubbish parameters.
Generally speaking, you shouldn't throw BadDataException because you shouldn't use Exceptions to control program flow. Exceptions are for the exceptional. Callers to your method can know before they call it if their strings are numbers or not, so passing rubbish in is avoidable and therefore can be considered a programming error, which means it's OK to throw unchecked exceptions.
Regarding declaring throws NumberFormatException - this is not that useful, because few will notice due to NumberFormatException being unchecked. However, IDE's can make use of it and offer to wrap in try/catch correctly. A good option is to use javadoc as well, eg:
/**
* Adds two string numbers
* #param a
* #param b
* #return
* #throws NumberFormatException if either of a or b is not an integer
*/
public static int sum(String a, String b) throws NumberFormatException {
int x = Integer.parseInt(a);
int y = Integer.parseInt(b);
return x + y;
}
EDITED:
The commenters have made valid points. You need to consider how this will be used and the overall design of your app.
If the method will be used all over the place, and it's important that all callers handle problems, the declare the method as throwing a checked exception (forcing callers to deal with problems), but cluttering the code with try/catch blocks.
If on the other hand we are using this method with data we trust, then declare it as above, because it is not expected to ever explode and you avoid the code clutter of essentially unnecessary try/catch blocks.
Number 4. As given, this method should not take strings as parameters it should take integers. In which case (since java wraps instead of overflowing) there's no possibility of an exception.
x = sum(Integer.parseInt(a), Integer.parseInt(b))
is a lot clearer as to what is meant than
x = sum(a, b)
You want the exception to happen as close to the source (input) as possible.
As to options 1-3, you don't define an exception because you expect your callers to assume that otherwise your code can't fail, you define an exception to define what happens under known failure conditions WHICH ARE UNIQUE TO YOUR METHOD. I.e. if you have a method that is a wrapper around another object, and it throws an exception then pass it along. Only if the exception is unique to your method should you throw a custom exception (frex, in your example, if sum was supposed to only return positive results, then checking for that and throwing an exception would be appropriate, if on the other hand java threw an overflow exception instead of wrapping, then you would pass that along, not define it in your signature, rename it, or eat it).
Update in response to update of the question:
So, briefly: how do I implement SHOULD semantics if I only have MUST libraries.
The solution to this is to to wrap the MUST library, and return a SHOULD value. In this case, a function that returns an Integer. Write a function that takes a string and returns an Integer object -- either it works, or it returns null (like guava's Ints.tryParse). Do your validation seperate from your operation, your operation should take ints. Whether your operation gets called with default values when you have invalid input, or you do something else, will depend upon your specs -- most I can say about that, is that it's really unlikely that the place to make that decision is in the operation method.
1. I should specify NumberFormatException as a part of method's signature.
I think so. It's a nice documentation.
2. I should define my own checked exception (BadDataException), handle NumberFormatException inside the method and re-throw it as BadDataException.
Sometimes yes. The checked exceptions are consider to be better in some cases, but working with them is quite a PITA. That's why many frameworks (e.g., Hibernate) use runtime exceptions only.
3. I should define my own checked exception (BadDataException), validate both strings some way like regular expressions and throw my BadDataException if it doesn't match.
Never. More work, less speed (unless you expect throwing the exception to be a rule), and no gain at all.
4. Your idea?
None at all.
Nr 4.
I think I wouldn't change the method at all.
I would put a try catch around the calling method or higher in the stack-trace where I'm in a context where I can gracefully recover with business logic from the exception.
I wouldn't certainty do #3 as I deem it overkill.
Assuming that what you are writing is going to be consumed (like as an API) by someone else, then you should go with 1, NumberFormatException is specifically for the purpose of communicating such exceptions and should be used.
First you need to ask your self, does the user of my method needs to worry about entering wrong data, or is it expected of him to enter proper data (in this case String).
This expectation is also know as design by contract.
and 3. Yes you probably should define BadDataException or even better use some of the excising ones like NumberFormatException but rather the leaving the standard message to be show. Catch NumberFormatException in the method and re-throw it with your message, not forgetting to include the original stack trace.
It depends on the situation bu I would probably go with re-throwing NumberFormatException with some additional info. And also there must be a javadoc explanation of what are the expected values for String a, String b
Depends a lot on the scenario you are in.
Case 1. Its always you who debug the code and no one else and exception wont cause a bad user experience
Throw the default NumberFormatException
Case2: Code should be extremely maintainable and understandable
Define your own exception and add lot more data for debugging while throwing it.
You dont need regex checks as, its gonna go to exception on bad input anyway.
If it was a production level code, my idea would be to define more than one custom exceptions, like
Number format exception
Overflow exception
Null exception etc...
and deal with all these seperately
You may do so, to make it clear that this can happen for incorrect input. It might help someone using your code to remember handling this situation. More specifically, you're making it clear that you don't handle it in the code yourself, or return some specific value instead. Of course, the JavaDoc should make this clear too.
Only if you want to force the caller to deal with a checked exception.
That seems like overkill. Rely on the parsing to detect bad input.
Overal, a NumberFormaException is unchecked because it is expected that correctly parseable input is provided. Input validation is something you should handle. However, actually parsing the input is the easiest way to do this. You could simply leave your method as it is and warn in the documentation that correct input is expected and anyone calling your function should validate both inputs before using it.
Any exceptional behaviour should be clarified in the documentation. Either it should state that this method returns a special value in case the of failure (like null, by changing the return type to Integer) or case 1 should be used. Having it explicit in the method's signature lets the user ignore it if he ensures correct strings by other means, but it still is obvious that the method doesn't handle this kind of failure by itself.
Answer to your updated question.
Yes it's perfectly normal to get "surprise" exceptions.
Think about all the run time errors one got when new to programming.
e.g ArrayIndexOutofBound
Also a common surprise exception from the for each loop.
ConcurrentModificationException or something like that
While I agree with the answer that the runtime exception should be allowed to be percolated, from a design and usability perspective, it would be a good idea to wrap it into a IllegalArgumentException rather than throw it as NumberFormatException. This then makes the contract of your method more clear whereby it declares an illegal argument was passed to it due to which it threw an exception.
Regarding the update to the question "Imagine, it's not an open-source framework, that you should use for some reason. You look at method's signature and think - "OK, it never throws". Then, some day, you got an exception. Is it normal?" the javadoc of your method should always spill out the behavior of your method (pre and post constraints). Think on the lines of say collection interfaces where in if a null is not allowed the javadoc says that a null pointer exception will be thrown although it is never part of the method signature.
As you are talking about good java practice ,in my opinion it is always better
To handle the unchecked exception then analyze it and through a custom unchecked exception.
Also while throwing custom unchecked exception you can add the Exception message that your client could understand and also print the stack trace of original exception
No need to declare custom exception as "throws" as it is unchecked one.
This way you are not violating the use of what unchecked exceptions are made for, at the same time client of the code would easily understand the reason and solution for the exception .
Also documenting properly in java-doc is a good practice and helps a lot.
I think it depends on your purpose, but I would document it at a minimum:
/**
* #return the sum (as an int) of the two strings
* #throws NumberFormatException if either string can't be converted to an Integer
*/
public static int sum(String a, String b)
int x = Integer.parseInt(a);
int y = Integer.parseInt(b);
return x + y;
}
Or, take a page from the Java source code for the java.lang.Integer class:
public static int parseInt(java.lang.String string) throws java.lang.NumberFormatException;
How about the input validation pattern implemented by Google's 'Guava' library or Apache's 'Validator' library (comparison)?
In my experience, it is considered good practice to validate a function's parameters at the beginning of the function and throw Exceptions where appropriate.
Also, I would consider this question to be largely language independent. The 'good practice' here would apply to all languages that have functions which can take parameters which may or may not be valid.
I think your very first sentence of "Quite a stupid question" is very relevant. Why would you ever write a method with that signature in the first place? Does it even make sense to sum two strings? If the calling method wants to sum two strings, it is the calling method's responsibility to make sure they are valid ints and to convert them before calling the method.
In this example, if the calling method cannot convert the two Strings into an int, it could do several things. It really depends at what layer this summation occurs at. I am assuming the String conversion would be very close to front-end code (if it was done properly), such that case 1. would be the most likely:
Set an error message and stop processing or redirect to an error page
Return false (ie, it would put the sum into some other object and would not be required to return it)
Throw some BadDataException as you are suggesting, but unless the summation of these two numbers is very important, this is overkill, and like mentioned above, this is probably bad design since it implies that the conversion is being done in the wrong place
There are lots of interesting answers to this question. But I still want to add this :
For string parsing, I always prefer to use "regular expressions". The java.util.regex package is there to help us. So I will end up with something like this, that never throws any exception. It's up to me to return a special value if I want to catch some error :
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public static int sum(String a, String b) {
final String REGEX = "\\d"; // a single digit
Pattern pattern = Pattern.compile(REGEX);
Matcher matcher = pattern.matcher(a);
if (matcher.find()) { x = Integer.matcher.group(); }
Matcher matcher = pattern.matcher(b);
if (matcher.find()) { y = Integer.matcher.group(); }
return x + y;
}
As one can see, the code is just a bit longer, but we can handle what we want (and set default values for x and y, control what happens with else clauses, etc...)
We could even write a more general transformation routine, to which we can pass strings, defaut return values, REGEX code to compile, error messages to throw, ...
Hope It was usefull.
Warning : I was not able to test this code, so please excuse eventual syntax problems.
You face this issue because you let user errors propagate too deep into the core of the application and partly also because you abuse Java data types.
You should have a clearer separation between user input validation and business logic, use proper data typing, and this problem will disappear by itself.
The fact is the semantics of Integer.parseInt() are known - it's primary purpose it to parse valid integers. You're missing an explicit user input validation/parsing step.
Are there any hard and fast rules regarding returning boolean in a method signature to indicate a successful operation as opposed to declaring void? I find that for more critical operations in my calling method I want to know if an operation completed so I can log any issues. Is this an "inappropriate" use of boolean?
Usually I use Exceptions to signal when something went wrong.
Instead of returning false, you can throw an Exception with a detailed message about what the problem was.
Returning false doesn't give you much information about the problem.
Then, instead of checking for a false return value, just put the method call in try/catch if you expect that the method could easily fail.
Many people will complain that this method is slower. But, the benefits you gain greatly outweigh the slowdown. Besides, if you are using Java speed shouldn't be your #1 concern.
I generally find that throwing an exception in the case of a failure is a far better solution than returning a boolean, because generally do not care if the process has succeeded - I only care if it's failed. By using an exception I can provide any amount of information about why the process actually failed.
If exceptions seem distasteful, you can return a custom Status object which contains a boolean and a status message (something like "Added 6 new Foobars!" or "Could not add Foobars because the Foobin is full!"), although that is of course more complex.
Only do this in scenarios where it's clear that something has a boolean outcome. Like IsValidCustomer() or some such.
For all other things where you think you could introduce it, it probably means you're dealing with some kind of Exception, and you really don't want to wrap that with a simple boolean true/false, because you can have a variety of flavours (different exceptions) and reasons why something goes wrong, which you would want to know about.
So either let the exception bubble up the stack, or catch it and turn it into a custom exception or log it or whatever.
Use boolean values to indicate non-exceptional failure outcomes. An example would be a search function. The nominal failure would be not-found. Communicating that outcome with exceptions is unwieldy. Save exceptions for exceptional cases; the difference between not-found and cannot-search.
This is an ok paradigm, but if you want to force the caller to handle the case wehre the operation doesn't complete successfully, you might want to throw a checked exception instead.
This pattern does occur in the core Java libraries, though. See File.delete() as an example.
For returning success generally what you see is:
Return a boolean
Return void, but throw exception on error
Return a status code (less common in java).
Can't see anything wrong with returning a boolean for success, unless you'd need information on exception behavior.
If there is an unexpected result, throw an exception.
If you just want the function to tell you "did I do X" then return a boolean.
In practice, I find that throwing an Exception is the best thing to do when failure means that we need to abort the process. Like, if you're trying to process an order -- bill the customer, arrange shipping, pay sales taxes, etc -- if you can't find the order record, there's probably little point in doing all the other work. You just want to get out of there. Exceptions let you do this easily. Just catch at the bottom of the block, display or log the error, and get out.
On the other hand, if an "error" means that my program takes a different flow path, returning a boolean makes more sense. Like, if I'm looking for a specific customer and if he exists I update his record and if he doesn't I create a new customer record, then it makes a lot of sense to return a boolean, and in the caller test it and when true follow one path and when false the other.
Really this is two very different meanings of the word "error", and they call for different handling. It is quite possible that the same function could do both. Like, on found return true, on not found return false, on I/O error trying to read throw an exception.
It seem ok, but the devil lies into the details. ;-)
Throwing an exception is the main alternative, with pros and cons.
I think you could get more insight by providing precise coding samples...
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?
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.
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.
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.
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.
Also because exceptions are expensive in terms of performance
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!
It's a lot easier to deal with checking for a -1 than catching an exception.
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.
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.
Until the author of Java's string.indexOf tells us the actual history...
Let's suppose we had to design it from scratch, some obvious design constraints for this problem:
indexOf must return a numeric value, so that when a match is found, you know where it is
valid indexes are guaranteed to be always integers
array (and string) indexes are zero-based in Java
Java is strongly typed
the integer numeric types are signed in Java
Given those basic constraints, some possible choices for function return type the would be integer (ideally of a type large enough to represent the last index in the largest possible string), OR... Object (and perhaps return null to indicate not found). But in practice returning Object would be neither efficient nor user-friendly, due to the need to check its validity and cast before usage for the found case - so it's not really a viable option!
So let's go with an integer. Do we want to throw an exception if not found? Throwing exceptions has multiple problems of its own - creating exception objects and jumping to exception handlers can be quite inefficient, and writing try/catch blocks around indexOf calls is no fun either!
So let's say we've narrowed it down: it has to return a (signed) integer type, and not throw an exception. Now which integer value should it return to represent not found?
In order to allow searching in strings as large as possible, we should reserve all positive integers for usage as meaning successfully found. Conversely, none of the negative numbers is needed to represent a 'found' index, so all are potentially available to use as return codes representing 'not found'.
If we could have picked any negative number, to represent not found, or just said 'all negative return values mean not found' it would do the job... But would it be the best design?
What are some reasons to use -1 instead of other negative numbers? My favorite reasons are simply '-1 is easy for everyone to remember, and you can do exact equality tests on it'. (Instead of being forced to use inequalities and think about off-by-one problems like whether you want less-than or less-than-or-equal, and what value to compare with, zero or negative one)
I also sometimes admire Chris's reason that (paraphrasing) 'it works nicely with substring(foundIndex + 1)'.