I'm working on an IRC bot that should handle some user commands, lets take !login <username> <password> for example. Sometimes the user forgets to enter their password, so instead of sending !login myUser hunter2 they might use !login myUser. In this case, the user should be replied to with an error message. The method that actually handles the command handleCommand is always wrapped by another method wrapperMethod. Which of the following ways should I use to handle user errors: should handleCommand just message the user about what happened and exit itself, or should it throw an exception with the error message and let wrapperMethod do the rest? (String[] command is the original command without the ! and split by spaces, so !login myUser hunter2 would become {"login", "myUser", "hunter2"})
Using exceptions:
public void wrapperMethod(Object sender, Object receiver, String[] command) {
try {
handleCommand(sender, receiver, command);
catch(CommandExecutionException e) {
receiver.sendTo(sender, e.getMessage());
}
}
private void handleCommand(Object sender, Object receiver, String[] command) {
if(command.length != 3)
throw new CommandExecutionException("Things went wrong");
//Do things
}
Not using exceptions:
public void wrapperMethod(Object sender, Object receiver, String[] command) {
handleCommand(sender, receiver, command);
}
private void handleCommand(Object sender, Object receiver, String[] command)
if(command.length != 3) {
receiver.sendTo(sender, "Things went wrong");
return;
}
//Do things
}
Which type should I prefer and why? Right now, I'm thinking of going with exceptions simply because I can save a few lines of code that I really don't need. When a user error is detected, handleCommand is always halted immediately. There's also the possiblility of having handleCommand return Optional<Error> or something like that, but this seems really fishy.
I prefer option with exceptions, because it separates normal processing from error handling.
In second option method handleCommand is responsible for both.
First option follows Single responsibility principle: method handleCommand handles correct flow, if something goes wrong throw exception and allow someone else cares the problem.
Moreover, assume that within section
//Do things
you find other error. If you use exception, you may keep consistent and clean pattern that any error triggers exception and someone who catch the exception cares correct handling.
Don't worry that exceptions are expensive; planes are more expensive that bikes, but if you go for vacation to Bali, use rather plane than bike (not applicable for Bali citizens:) ). Exceptions are designed for exceptions, as long as you don't use them in regular processing, it is OK.
Exceptions are expensive. Using them as flow control is strongly discouraged. It also means that your code could complete abruptly, and makes it harder to debug or read.
I'd go a different route: use Hibernate Validators. They're not difficult to set up or establish in your code, and using them means that your input is validated before you ever attempt to manipulate things. It also keeps your validation logic and actual business logic separate.
If you don't want to go that route, I'd encourage the latter approach - although, I'd use an else instead of return from a void method.
Related
void appendFile() throws IOException{
FileWriter print = new FileWriter(f, true);
String info = GetData.getWord("Write desired info to File");
print.append(" "); //Write Data
print.append(info);
System.out.println("this executes");
print.flush();
print.close();
}
boolean fileExist(){
return f.exists();
}
try{
if (f.fileExist())
f.appendFile();
else {
throw new IOException();
}
}
catch(IOException e) {
e.printStackTrace();
}
I'm not sure if the ecxeption is well handeled? The FileWriter is not going to be created if there is a fileNotFoundException, therefore don't need to be closed. However, is it possible that this code throws another kind of IOException after the file was opened?, and in that case do I need a finally block to close the file.
No.
It doesn't safely close the resource
The general rule is, if you call a constructor of an object that represents a closable resource, or a method that returns one which documents that this counts as 'opening the resource', which often but not always includes new being part of the method name (examples: socket.getInputStream(), Files.newInputStream), then you are responsible for closing it.
The problem is, what if an exception occurs? So, you have to use try/finally, except that's a mouthful, so there's a convenient syntax for this.
The appendFile method should use it; it isn't, that makes it bad code. This is correct:
try (FileWriter print = new FileWriter(f, true)) {
String info = GetData.getWord("Write desired info to File");
print.append(" "); //Write Data
print.append(info);
System.out.println("this executes");
}
Not how it is not neccessary to flush before close (close implies flush), and in this case, not neccessary to close() - the try construct does it for you. It also does it for you if you get out of the {} of the try via a return statement, via control flow (break), or via an exception, or just by running to the } and exiting normally. No matter how - the resource is closed. As it should be.
It throws description-less exceptions
else throw new IOException(); is no good; add a description that explains why the exception happened. throw new IOException("File not found") is better, but throw new FileNotFoundException(f.toString()) is even better: The message should convey useful information and nothing more than that (in other words, throw new IOException("Something went wrong") is horrible, don't do that, that message adds no useful information), should not end in punctuation (throw new IOException("File not found!") is bad), and should throw a type that is most appropriate (if the file isn't there, FileNotFoundException, which is a subtype of IOException, is more appropriate, obviously).
It commits the capital offense
You should not ever write a catch block whose contents are just e.printStackTrace();. This is always wrong.
Here's what you do with a checked exception:
First, think of what the exception means and whether the nature of your method inherently implies that this exception can occur (vs. that it is an implementation detail). In this case, you didn't show us what the method containing that try/catch stuff even does. But let's say it is called appendFile, obviously a method that includes the text 'file' does I/O, and therefore, that method should be declared with throws IOException. It's not an implementation detail that a method named appendFile interacts with files. It is its nature.
This is somewhat in the eye of the beholder. Imagine a method named saveGame. That's less clear; perhaps the mechanism to save may involve a database instead, in which case SQLException would be normal. That's an example of a method where 'it interacts with the file system' is an implementation detail.
The problem that the exception signals is logical, but needs to be more abstract.
See the above: A save file system can obviously fail to save, but the exact nature of the error is abstract: If the save file system is DB-based, errors would show up in the form of an SQLException; if a file system, IOException, etcetera. However, the idea that saving may fail, and that the code that tried to save has a reasonable chance that it can somewhat recover from this, is obvious. If it's a game, there's a user interface; you should most absolutely TELL the player that saving failed, instead of shunting some stack trace into sysout which they probably never even look at! Telling the user that something failed is one way of handling things, not always the best, but here it applies).
In such cases, make your own exception type and throw that, using the wrapper constructor:
public class SaveException extends Exception {
public SaveException(Throwable cause) {
super(cause);
}
}
// and to use:
public void save() throws SaveException {
try {
try (OutputStream out = Files.newOutputStream(savePath)) {
game.saveTo(out);
}
} catch (IOException e) {
throw new SaveException(e);
}
}
If neither applies, then perhaps the exception is either essentially not handleable or not expectable or nearly always a bug. For example, writing to an outputstream that you know is a ByteArrayOutputStream (which can't throw), trying to load the UTF-8 charset (which is guaranteed by the JVM spec and therefore cannot possibly throw NoSuchCharsetException) - those are not expectable. Something like Pattern.compile("Some-regexp-here") can fail (not all strings are valid regexps), but as the vast majority of regexes in java are literals written by a programmer, any error in them is therefore neccessarily a bug. Those, too, are properly done as RuntimeExceptions (which are exceptions you don't have to catch or list in your throws line). Not handleables are mostly an application logic level thing. All fair game for runtimeexceptions. Make your own or use something that applies:
public void save(int saveSlot) {
if (saveSlot < 1 || saveSlot > 9) throw new IllegalArgumentException("Choose a saveslot from 1 to 9");
// ... rest of code.
}
This really feels like door number one: Whatever method this is in probably needs to be declared as throws IOException and do no catching or trying at all.
Minor nit: Uses old API
There's new API for file stuff in the java.nio.file package. It's 'better', in that the old API does a bunch of bad things, such as returning failure by way of a boolean flag instead of doing it right (by throwing an exception), and the new API has far more support for various bits and bobs of what file systems do, such as support for file links and creation timestamps.
when a function or method encouter error/invalid data, do return false or throw an exception?
Consider a class Loginer has such method :
public boolean login(String username){
//retrieve data...
if(username.equals(record.username)){
return true;
}
return false;
}
then at the main or some other class
String username = "ggwp";
if(Loginer.login(username)){
//successful login, show homepage...
new User(username);
} else {
//invalid username
}
won't it be inefficient as it has been checked two time with if-else statement, one in Loginer, and another one check for true again at main.
won't try catch will do the same? having the Loginer to throw an Exception:
public User login(String username){
//retrieve record data...
if(username.equals(record.username)){
return new User(username);
}
/* Exception if no record found for such username */
throw new MyException("invalid username");
}
then on the main:
String username = "ggwp2";
User theUser;
try{
//sucessful login
theUser = Loginer.login(username);
}catch(MyException e){
//invalid username
}
the try-catch need no check second time for true or false. (this example i use return User object, it could be void and return nothing but the point is, why use boolean which will eventual being check twice?)
some website sources say not to use try-catch for 'code jumping' but in this case it just do the same. (try-catch is just too similar to if-else statement)
So which is correct and why? please guide and sorry if this question is incorrect, im newbie to OO.
Short answer:
You should NEVER use try/catch for "control logic".
As Andy Turner said, "Use exceptions to handle exceptional conditions only."
This is equally true of all languages that support exceptions - not just Java. Useful article:
Best practices for exceptions
PS: try/catch is NOT "just similar" to "if/else". It has a different implementation, a different intent ... and it's FAR more expensive.
ADDITIONAL NOTE:
Exceptions: Why throw early? Why catch late?
https://softwareengineering.stackexchange.com/questions/231057/exceptions-why-throw-early-why-catch-late
In my experience, its best to throw exceptions at the point where the
errors occur. You do this because it's the point where you know the
most about why the exception was triggered.
As the exception unwinds back up the layers, catching and rethrowing
is a good way to add additional context to the exception. This can
mean throwing a different type of exception, but include the original
exception when you do this.
Eventually the exception will reach a layer where you are able to make
decisions on code flow (e.g a prompt the user for action). This is the
point where you should finally handle the exception and continue
normal execution.
With practice and experience with your code base it becomes quite easy
to judge when to add additional context to errors, and where it's most
sensible to actually, finally handle the errors.
Catch → Rethrow
Do this where you can usefully add more information that would save
a developer having to work through all the layers to understand the
problem.
Catch → Handle
Do this where you can make final decisions on what is an
appropriate, but different execution flow through the software.
Catch → Error Return
Whilst there are situations where this is appropriate, catching
exceptions and returning an error value to the caller should be
considered for refactoring into a Catch → Rethrow implementation.
For example I have something like this:
public void saveFoodatas(List<Foodata> foodataList) {
DatabaseHelper.database.beginTransaction();
try {
for (Foodata foodata : foodataList) {
saveFoodata(foodata);
}
DatabaseHelper.database.setTransactionSuccessful();
}
finally {
DatabaseHelper.database.endTransaction();
}
}
Where DatabaseHelper is a class extending SQLiteOpenHelper and database is a SQLiteDatabase.
In this function I am trying to make it so you save/commit a lot of objects to the database, but if there is a failure, then don't commit any of the changes.
I believe that what it's currently set up to do correctly (if there is an error, it leaves the try block I think and goes straight to finally since there is no catch), but my question is how to properly trigger the failure condition. Do I need saveFoodata to "throw an exception"? If the function encounters some kind of failure without me doing any try/catch/throwing, does that count too? How exactly do I handle saveFooData()?
I think you are on the right track. You need to abort the transaction if an error occurs. You also need to alert the user of the problem. This means that saveFoodata() and saveFoodatas() should throw an exception so that the UI code can display a message to the user,
I have a builder for a class with the following method which uses the Google libphonenumber library.
public final Builder withPhoneNumber(String phoneNumber, String region)
throws NumberParseException,IllegalArgumentException {
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
if (!phoneUtil.getSupportedRegions().contains(region)) {
throw new IllegalArgumentException("Region code is invalid.");
}
PhoneNumber inputNumber = phoneUtil.parse(phoneNumber, region);
String formattedNumber = phoneUtil.format(inputNumber, PhoneNumberFormat.E164);
this.phoneNumbers.add(formatterNumber);
return this;
}
The method needs to check that the phoneNumber argument is a valid form and that the region argument is one of the allowable regions. Normally if this was just a mutator method for the class not the builder I'd just handle the exceptions internally and return false if one occurs, but since I'm limited to returning the Builder type I cannot return a boolean. Would it be better to propagate the exception to the user as I have done above (requiring the user to surround their builder call with try catch blocks) or should I just manage the exceptions internally by returning the unchanged builder (i.e. rejecting the new phone number if it's invalid)? My only concern with the second option is that the user is not notified why the method call isn't adding the phone number to the builder, but I suppose I could just put that in javadoc.
What should I do?
The code snippet that you posted seems the right approach to me. I don't think you have any reason to be worried because:
The IllegalArgumentException is not a checked exception, so you're not forcing clients to surround the building code in try/catch blocks.
The input is usually supposed to be validated before you start building your domain objects. The validation logic should guard the UI input and not allow any transaction to begin until the input data is valid.
The second bullet means that inside your builder you just perform a double-check, and not the actual validation which results in error messages in the UI.
You can think about it this way: what if the input was null (for either phoneNumber or region). Most likely, that will result in a NullPointerException, which is the correct behavior. And you don't expect clients to catch the NPE; they're just not supposed to call your method with that kind of input.
Is there a better way for catching specific Exception with a message then doing this:
try{
methodThatWillProbablyThrowASocketException();
} catch(SocketException e){
if(e.getMessage().contains("reset")){
// the connection was reset
// will ignore
} else{
throw e;
}
}
For example the HttpStatusException gives me the Method getStatusCode() where i can easily compare if the error status was 404 or 502 and the can decide what to do:
try{
methodThatWillProbablyThrowAHTTPException();
} catch(HttpStatusException e){
if(e.getStatusCode() == 404){
// not found, will not continue
}
if else(e.getStatusCode() == 502){
// server errror, try again
} else{
throw e;
}
}
Most other Exceptions dont give me prober Methods, just the Message.
So my question is, is it the right way to do it? With String compares? Or is there a better way?
Just do one thing .
Collect all types of exception that are likely to be occur for your project.
Make a separate class by extending Exception.
Override the getCause() method.
http://docs.oracle.com/javase/6/docs/api/java/lang/Throwable.html#getCause%28%29
public Throwable getCause()
Define codes you want for different exceptions Like null-pointer 101 ,, so on......
The use that class every where . So you have to write exception only once and you can use with as many projects.
After building the class it will be reusable for all your needs
If you getting new conditions, update this class only and all the things will be done
This is a better solution according to me...
This way you can get functionality for which you are looking. you have to make it by yourself.
Relying on code or status code is fine but relying on message could be problematic as the message can change.
You should look to refactor and define multiple exceptions or define codes for different scenarios.