This is my first time posting a question so I apologize if I am vague or unclear. I'm still learning some of the essentials of Java and I came across a tutorial online regarding exceptions. The entire thing can be found here: Java World: Exceptions in Java.
This may be a dumb question but I'm having difficulty understanding it.
class VirtualCafe {
public static void serveCustomer(VirtualPerson cust,
CoffeeCup cup) {
try {
cust.drinkCoffee(cup);
System.out.println("Coffee tastes just right.");
}
catch (UnusualTasteException e) {
System.out.println(
"Customer is complaining of an unusual taste.");
String s = e.getMessage();
if (s != null) {
System.out.println(s);
}
// Deal with an unhappy customer...
}
}
}
I'm having trouble understanding why would you want to store a string object and then have it print if the previous println seemed like it took care of the problem. What exactly does the second println print out? drinkCoffee() throws a few types of Exceptions including UnusualTasteException. I'd appreciate any feedback!
Here's the code for UnusualTasteExpection:
class UnusualTasteException extends Exception {
UnusualTasteException() { }
UnusualTasteException(String msg) {
super(msg);
}
}
To give an example, if the exception is thrown like this:
throw new UnusualTasteException("The coffee is very bitter");
the println() you're asking about would print out The coffee is very bitter, which is more informative than the generic "unusual taste" message.
This code (sort of) highlights a couple of things:
Catching exceptions and getting meaningful information from them
Dealing with null when it's undesirable to allow around
So, let's be explicit - the code in the catch block is dealing with whatever error message we bring back from the drinkCoffee method thrown by the UnusualTasteException. That said, we print a more generic message about the fact that the customer had an unusual taste with their coffee.
The second println concerns if we had anything meaningful to learn from the exception; a message or a clue or something. It could also be the case that someone passed in null to the constructor in this manner:
throw new UnusualTasteException((String) null);
...or more innocuously:
String msg = null;
throw new UnusualTasteException(msg);
If we don't have anything meaningful to print out, then we don't print it out. We also want to avoid repeated calls to the method, so we store the result of the call into a variable. This is what the second block accomplishes.
As a general aside, this is considered using exceptions as flow control, because there are any number of ways to handle this scenario appropriately (an enum for satisfaction of taste, or a boolean for whether they liked it or not stored on the drinker). In general, it's considered poor practice because exceptions are incredibly expensive to generate, and should be reserved for something truly exceptional.
So your code (within drinkCoffee method) would be doing something like to throw an exception:
throw new UnusualTasteException ("Weird coffee taste!!!");
If you see Exception class's parent i.e. Throwable has a field called detailMessage and then when you call above constructor to throw an exception, it will set detailMessage field.
And that's what you are using in your second print statement. So your print statement would print "Weird coffee taste!!!"
By doing so, you get exact string and intention of exception. And you might be throwing same exception from tea, lemon etc. but if you were processing flow for coffee, you see that it was weird taste of coffee and not lemon or tea and so on.
Related
I'm worried that this is a runtime exception so it should probably be used sparingly.
Standard use case:
void setPercentage(int pct) {
if( pct < 0 || pct > 100) {
throw new IllegalArgumentException("bad percent");
}
}
But that seems like it would force the following design:
public void computeScore() throws MyPackageException {
try {
setPercentage(userInputPercent);
}
catch(IllegalArgumentException exc){
throw new MyPackageException(exc);
}
}
To get it back to being a checked exception.
Okay, but let's go with that. If you give bad input, you get a runtime error. So firstly that's actually a fairly difficult policy to implement uniformly, because you could have to do the very opposite conversion:
public void scanEmail(String emailStr, InputStream mime) {
try {
EmailAddress parsedAddress = EmailUtil.parse(emailStr);
}
catch(ParseException exc){
throw new IllegalArgumentException("bad email", exc);
}
}
And worse - while checking 0 <= pct && pct <= 100 the client code could be expected to do statically, this is not so for more advanced data such as an email address, or worse, something that has to be checked against a database, therefore in general client code cannot pre-validate.
So basically what I'm saying is I don't see a meaningful consistent policy for the use of IllegalArgumentException. It seems it should not be used and we should stick to our own checked exceptions. What is a good use case to throw this?
The API doc for IllegalArgumentException:
Thrown to indicate that a method has been passed an illegal or inappropriate argument.
From looking at how it is used in the JDK libraries, I would say:
It seems like a defensive measure to complain about obviously bad input before the input can get into the works and cause something to fail halfway through with a nonsensical error message.
It's used for cases where it would be too annoying to throw a checked exception (although it makes an appearance in the java.lang.reflect code, where concern about ridiculous levels of checked-exception-throwing is not otherwise apparent).
I would use IllegalArgumentException to do last ditch defensive argument checking for common utilities (trying to stay consistent with the JDK usage). Or where the expectation is that a bad argument is a programmer error, similar to an NullPointerException. I wouldn't use it to implement validation in business code. I certainly wouldn't use it for the email example.
When talking about "bad input", you should consider where the input is coming from.
Is the input entered by a user or another external system you don't control, you should expect the input to be invalid, and always validate it. It's perfectly ok to throw a checked exception in this case. Your application should 'recover' from this exception by providing an error message to the user.
If the input originates from your own system, e.g. your database, or some other parts of your application, you should be able to rely on it to be valid (it should have been validated before it got there). In this case it's perfectly ok to throw an unchecked exception like an IllegalArgumentException, which should not be caught (in general you should never catch unchecked exceptions). It is a programmer's error that the invalid value got there in the first place ;) You need to fix it.
Throwing runtime exceptions "sparingly" isn't really a good policy -- Effective Java recommends that you use checked exceptions when the caller can reasonably be expected to recover. (Programmer error is a specific example: if a particular case indicates programmer error, then you should throw an unchecked exception; you want the programmer to have a stack trace of where the logic problem occurred, not to try to handle it yourself.)
If there's no hope of recovery, then feel free to use unchecked exceptions; there's no point in catching them, so that's perfectly fine.
It's not 100% clear from your example which case this example is in your code, though.
Treat IllegalArgumentException as a preconditions check, and consider the design principle: A public method should both know and publicly document its own preconditions.
I would agree this example is correct:
void setPercentage(int pct) {
if( pct < 0 || pct > 100) {
throw new IllegalArgumentException("bad percent");
}
}
If EmailUtil is opaque, meaning there's some reason the preconditions cannot be described to the end-user, then a checked exception is correct. The second version, corrected for this design:
import com.someoneelse.EmailUtil;
public void scanEmail(String emailStr, InputStream mime) throws ParseException {
EmailAddress parsedAddress = EmailUtil.parseAddress(emailStr);
}
If EmailUtil is transparent, for instance maybe it's a private method owned by the class under question, IllegalArgumentException is correct if and only if its preconditions can be described in the function documentation. This is a correct version as well:
/** #param String email An email with an address in the form abc#xyz.com
* with no nested comments, periods or other nonsense.
*/
public String scanEmail(String email)
if (!addressIsProperlyFormatted(email)) {
throw new IllegalArgumentException("invalid address");
}
return parseEmail(emailAddr);
}
private String parseEmail(String emailS) {
// Assumes email is valid
boolean parsesJustFine = true;
// Parse logic
if (!parsesJustFine) {
// As a private method it is an internal error if address is improperly
// formatted. This is an internal error to the class implementation.
throw new AssertError("Internal error");
}
}
This design could go either way.
If preconditions are expensive to describe, or if the class is intended to be used by clients who don't know whether their emails are valid, then use ParseException. The top level method here is named scanEmail which hints the end user intends to send unstudied email through so this is likely correct.
If preconditions can be described in function documentation, and the class does not intent for invalid input and therefore programmer error is indicated, use IllegalArgumentException. Although not "checked" the "check" moves to the Javadoc documenting the function, which the client is expected to adhere to. IllegalArgumentException where the client can't tell their argument is illegal beforehand is wrong.
A note on IllegalStateException: This means "this object's internal state (private instance variables) is not able to perform this action." The end user cannot see private state so loosely speaking it takes precedence over IllegalArgumentException in the case where the client call has no way to know the object's state is inconsistent. I don't have a good explanation when it's preferred over checked exceptions, although things like initializing twice, or losing a database connection that isn't recovered, are examples.
As specified in oracle official tutorial , it states that:
If a client can reasonably be expected to recover from an exception,
make it a checked exception. If a client cannot do anything to recover
from the exception, make it an unchecked exception.
If I have an Application interacting with database using JDBC , And I have a method that takes the argument as the int item and double price. The price for corresponding item is read from database table. I simply multiply the total number of item purchased with the price value and return the result. Although I am always sure at my end(Application end) that price field value in the table could never be negative .But what if the price value comes out negative? It shows that there is a serious issue with the database side. Perhaps wrong price entry by the operator. This is the kind of issue that the other part of application calling that method can't anticipate and can't recover from it. It is a BUG in your database. So , and IllegalArguementException() should be thrown in this case which would state that the price can't be negative.
I hope that I have expressed my point clearly..
Any API should check the validity of the every parameter of any public method before executing it:
void setPercentage(int pct, AnObject object) {
if( pct < 0 || pct > 100) {
throw new IllegalArgumentException("pct has an invalid value");
}
if (object == null) {
throw new IllegalArgumentException("object is null");
}
}
They represent 99.9% of the times errors in the application because it is asking for impossible operations so in the end they are bugs that should crash the application (so it is a non recoverable error).
In this case and following the approach of fail fast you should let the application finish to avoid corrupting the application state.
Recently, I can across some code that made me a little confused:
I was always under the impression that doing return this way was bad practice. For one, there is no way to know if something went wrong other than looking in the logs. I asked around a bit and the general notion seems to be that throwing an exception would lead to bad code because people may catch the exception and do nothing with it. Is this really a good reason to not throw an exception? If so, is there any other way that this can be handled?
public void checkThisOut() {
String str = null;
str = someMethodThatCanReturnNull();
if(str == null) {
//log error
return;
}
}
Another example would be the following: What is the difference between break and return in this context? Is one preferable over the other?
public void update() {
List<Object> objects = SomeClass.findObjects();
for( Object o : objects ) {
if( o.getSomething().equals("some value" ) ) {
o.doSomething();
return;
}
}
}
Throwing an exception with the intent that it is used to control flow (e.g. if(a) then do b, else if exception then do c) in your app is generally considered bad practice.
However in your first example, if you're expecting a result to be not null and you do receive a null, and if this is an unexpected error condition from which you can't continue, then this is a good example of when to throw an exception.
When code throws an exception, the caller has the choice how to react. If errors are just logged but not propagated to the caller - then the caller does not even know about the error.
Therefore that argument to not throw is nonsense. When you are afraid that other people write bad code - then you educate them to do better. You don't start writing bad code yourself. But when throwing an exception properly documented why and when that happens.
For the second case: no difference in resulting behavior. So style only - do what your team does normally.
Throwing an exception is not bad code. You just should not use exceptions for regular controlflow.
For your second example, break and return are equal, but I would use return as it does make the intention slightly clearer. If you want to do something after the loop, you can change it to break then.
throwing an exception would lead to bad code because people may catch the exception and do nothing with it
I disagree with writing bad code to avoid other bad code. If the null return value is indicates an error, then you should throw an exception.
For your second question: break and return don't make any difference here because there is nothing after the for loop.
It would make a difference if you add code after the for loop, in which case return exits the method completely, while break jumps at the end of the for loop.
None is better than the other, it depends on what you intent to do. Return is probably clearer and quickier (simpler to understand), but many people think that a method should only have a single return at its end and having two or more is bad practice (because it makes the code harder to understand)
Think what would seem the most logical to you if you had to return a value in case the object you are searching isn't found, like indexOf which returns -1: store the found item in a variable, break the loop and have a single return at the end, or have two return statements in the method. Both are correct ways to go.
This question already has answers here:
Can the JVM recover from an OutOfMemoryError without a restart
(7 answers)
Closed 6 years ago.
Here says that it is impossible to recover from errors.
I am not sure what does it mean because I can catch Error just like Exception.
Eg:
public static void main(String args[]) {
while (true) {
try {
throw new StackOverflowError("stackoverflow");
} catch (Throwable throwable) {
//do something
}
//program recover and continue to execute
}
}
The above program execute normally and It seems that It's possible to recover from errors. Can anyone help?
UPDATE:
example of stackoverflow is a little puzzling, only idiot want to recover from stackoverflow. Here is another example about OutOfMemory:
public class Main {
public static Map<Long, Object> cache = null;
public static void main(String args[]){
while(true){
try {
if(cache == null) {
cache = new HashMap<>();
}
for (long i = 0; i < Long.MAX_VALUE; ++i) {
cache.put(i, i);
}
}catch(OutOfMemoryError error) {
cache.clear();//delete some unused entry or clear all.
cache = null;
System.gc();
System.out.println("release memory");
}
}
}
}
It's a simple HashMap cache, execute the code using java -Xmx1m Main , and we will see an OutOfMemoryError soon, then release memory manually, and the program will continue to execute. insert-> OutOfMemoryError -> release -> insert...
See? the program have recovered from an OutOfMemoryError. Isn't it? And I think it's meaningful. So, Why someone still said program can't recover from OutOfMemoryError.
Obviously, the mere ability to "catch" an exception does not mean that you will (always ...) be able to "recover from" it ...
... i.e.: "to sally forth, entirely unscathed, as though 'such an inconvenient event' never had occurred in the first place."
I think that the essential point of the original author is more-or-less that: Even though the poor souls on the Titanic might have "caught" the fact that their ship was sinking, there was nothing that they could do to "recover" the ship and to sail it on unscathed to New York.
--- Edit:
"Now, let me add one more thought!" (As other Answerers have also done here.) Sometimes, an Error Exception is intentionally "thrown" in some block of code that has intentionally been surrounded by a catch-block.
Maybe the error (which is itself "an object") is of a particular user-defined type that the catcher will recognize. (He can "re-throw" any that he does not recognize, or simply decline to catch it.) This can be a very elegant and efficient way to handle, well, "the exceptions to the rule." (Hence the name...)
Whenever a block of code encounters a situation that "only happens once in a blue moon, but it just did," it can throw an exception high into the air, knowing that the nearest catcher will catch it. This catcher, in turn, can recognize the thing that just landed into his baseball-mitt, and respond accordingly. There can be any number of "catchers" out there, looking for different things.
This strategy is not "an Error," but rather an intentional alternative flow-of-control within the program.
Consider the following code which actually throws a StackOverflowError
public class Code
{
public static void main(String[] args)
{
try
{
f();
}
catch (Throwable t)
{
System.out.println("OK I'm recovered, let me try that again");
try
{
f();
}
catch (Throwable t2)
{
System.out.println("What's going on here??");
// let me try one more time..
try
{
f();
}
catch (Throwable t3)
{
System.out.println("Why can't I really recover");
}
}
}
}
// Bad recursion...
private static void f()
{
f();
}
}
Do you really want to continue with execution knowing that your code has such an issue? What if you need to call f() again somewhere down the line? You would want to have such code in production that tries to continue if a method keeps giving a StackOverflowError?
You're just catching the Throwable here, before it ever gets to the point where it's an error. Throwable is the superclass of both errors and exceptions. Therefore, a Throwable is not comparable to an error itself, much less a StackOverflowError, and your program is not recovering from an error.
An exception is sort of like a misdemeanor charge. It's not a fantastic thing to happen to you, or rather, your program, but it definitely won't land you in jail for extended periods of time. However, an error is dangerous - it is on the level of a felony, to continue this analogy. Java is considered safer than, say, C, because it will tell you when you are doing something that is unsafe. C, on the other hand, will allow you to access data that is beyond the scope of an array, for example, and you'll get awful bugs that are very difficult to debug that way.
The analogy to crime ends after that point. If you had scrolled down a little further on the page that you linked to, it continues to delineate the reasons why exceptions and errors are different, namely, that "errors are caused by the environment in which the application is running," and therefore, because your application is only in charge of itself, and not the actual environment, it cannot of its own volition recover from an error.
The page also gives the example of an OutOfMemoryError. While you, as the programmer, can plan ahead to try to prevent an OutOfMemoryError by making your code as efficient as you can, you won't be able to prevent such an error if the code is run on a machine that has, say, 1 byte of RAM. Errors cannot be caught because they are (mostly) out of the hands of the application itself. It's up to the programmer, such as in Michael Markidis' example, to not cause an error and avoid any error-causing programming techniques (such as using "Bad recursion") that will crash your program.
So, for a homework assignment, our professor wants us to try inserting an integer into an array of Strings:
public boolean addPerson(V person, int number)throws IllegalArgumentException{
if(numEntries < people.length){
people[numEntries] = person;
phones[numEntries] = number;
numEntries++;
return true;
}
return false;
}
public static void main(String[] args){
PhoneBook<String> names = new PhoneBook<String>();
PhoneBook<Integer> ssn = new PhoneBook<Integer>();
names.addPerson("john", 1235681213);
ssn.addPerson(123324567, 2048);
Integer soc = 132546789;
try{
names.addPerson(soc, 1996);
}
catch(IllegalArgumentException e){
System.out.println("You cannot enter a Social Security Number "
+ "into the Name phone book!");
}
But, this isn't working, and I still get the same error as without the try-catch. Any idea what I'm doing wrong?
EDIT
Sorry guys, I probably should've included the code for the addPerson method. I don't really know how to deal with exceptions yet.
What your professor likely wants you to observe is a compilation error. An array's type is fixed at instantation time, and will not change. The array will only ever accept whatever type it has been declared to accept, and nothing else.
Minor rant about exceptions to follow from here.
Let's have a quick chat about checked and unchecked exceptions. There is a difference between these two, and mixing them up can be painful at times.
Let's start with the checked exceptions. These are the exceptions that you must either explicitly catch yourself, or declare them to be thrown. Things along those lines are IOException, FileNotFoundException*, and a few others - pretty much anything that extends from the Exception class.
Java is telling you that you have the ability to recover from this error, and you as a good developer should ensure that your program does.
There are also unchecked exceptions; anything that extends RuntimeException or Error. These do not need to be declared to be thrown, as they occur during the runtime of the application, and there's really no guarantee if the program should recover from this error. An example of this would be ArithmeticException; should your application really recover if it tried to divide by zero? What state would it be in?
There are also some you really shouldn't be catching at all - what would you return to if you managed to catch an OutOfMemoryError? There isn't much you really can do at that point!
Now, to your code: you've declared an unchecked exception to be thrown. That's valid syntax, but Java isn't going to just arbitrarily throw the exception for you, because there isn't anything in that block of code that would just throw it. At worst, you could get an ArrayIndexOutOfBoundsException, but that's no IllegalArgumentException.
In order to actually throw that unchecked exception, you'd need to explicitly throw it:
throw new IllegalArgumentException();
...and you'd also need a good reason to do so. Exceptions are expensive.
*: I realize that FileNotFoundException is-an IOException. It's still checked.
I am trying to check whether the value passed by an user is valid constant or not. Here is the code I have written.
enum Media_Delivery {
Streaming, Progressive
}
public class TestMain {
public static void main(String[] args) {
String medi_delivery = "streaming";
try {
Media_Delivery.valueOf("streaming");
} catch (IllegalArgumentException e) {
System.out.print(e);
}
}
}
Now, in above code if the String passed is not withing the listed enum then it throws IllegalArgumentException which is obvious.
But my question is: Is this the proper way to validate? As we are using Java's exception mechanism to validate.
Can someone suggest a better idea or what I have coded above itself is the best option ?
-----EDIT--------
Another case which I wanted to discuss:
public class TestMain {
public static void main(String[] args) {
String inputPassed = "2a";
try {
Integer.parseInt(inputPassed);
} catch (NumberFormatException nfe) {
throw new SomeUserDefinedException("Please enter only numeric values");
}
}
So is this a good idea ? Or there should be our own parsing mechanism?
Exceptions should be used for exceptional conditions; things you don't expect to happen. Validating input isn't very exceptional.
Josh Bloch actually outlines this specifically in his book 'Effective Java' which IMHO is something every Java programmer should have.
EDIT: And this is actually a very good answer to how to approach the problem:
Check valid enum values before using enum
It is usually best practice not to catch or throw unchecked expressions (IllegalArgumentException is a RuntimeException which counts as "unchecked"). See the Java Tutorials - Exceptions for more details. If you can avoid it, try rewriting your code such that a runtime exception is not needed to be caught. This is a controversial issue, but runtime exceptions exist for a reason: they help the programmer identify bugs. If you catch them, then the bug is not being fixed, it is just being avoided. Try using an if-else statement?
According to the API, "the name must match exactly an identifier used to declare an enum constant." I believe this means the parameter is case-sensitive. In addition, the return type of the valueOf method is some type, not void, so you can't have that statement in the try block. try blocks should contain commands or void methods, such as int x = 3; or System.out.println(3); or something.
--------EDIT-------
OP, in response to your comment:
Like others here have said, it depends on what you're trying to accomplish. I assume that since you have the line Media_Delivery.valueOf("streaming"); in the try block, that you're attempting to see whether "streaming" is equal to one of the enum constants? In that case, you wouldn't need an if-else statement, you could simply write
boolean result = medi_delivery.equals(Media_Delivery.Streaming.name()) ||
medi_delivery.equals(Media_Delivery.Progressive.name());
System.out.println(result);
Or even better, if you don't want to have multiple || conditions, try a switch statement that cycles through each enum constant, testing the equality of the given string.
-Chris
PS: on naming convention, since enum constants are implicitly static final, it is common practice to declare them in all caps, such as STREAMING and PROGRESSIVE (the Java Tutorials - Enums).
I'd say it depends.
If input comes from GUI element like combobox or anything, where enum values are the only ones to choose - then your approach is ok. Here different value would really be an exception.
But if you're making console app, or textfiled with possibility to type anything then result different then enum values shouldn't be considered as exception. You should use normal if-else or cases with this approach.
generally: use exceptions only for exceptional cases, and not for something that is really likeable to happen.
There is no single "proper" way to validate, what you have would certainly be the way I would validate, but there are other ways(for instance you could put all the valid string values of the enumeration in a HashSet and then check against that set to see if its valid, that is probably what the valueOf method does anyway)
Now if the above approach is any "better" or not, that too is to be pretty subjective. If you are doing the validations in a loop and want to reject anything that contains invalid data, then the exception approach is probably best. If you want to flag all the inappropriate elements then either approach works.... the HashSet will probably be faster if there is a lot of problematic data as you wont have to generate a lot of new exception objects, but even then the difference in performance will be pretty negligible.