4

I have the following method, which needs to return a List, but exceptions might occur along the way, and I don't want to handle them in my application, mainly because I don't even know how to handle them. The idea is simple: read data from a CSV file and return the list instantiated using the 'Beans' logic in OpenCSV. The problem is the exceptions. Since I only want the error and stack trace to be printed in the console and the application to be terminated, what is the best approach to deal with this? Should I use throw? Should I use catch? The problem with catch is that the compiler complains that a return is missing, even if I provide it inside the try. This is not for a real application; it's just a simple study project, so if something goes wrong, I just want to know what happened and have the program terminate, nothing more.

public static List<Usuario> ler() {
    try (FileReader reader = new FileReader(UsuarioArquivo.getCaminho().toString())) {
        return new CsvToBeanBuilder<Usuario>(reader)
            .withType(Usuario.class)
            .build()
            .parse()
        ;
    }
}
candied_orange
  • 119,268

5 Answers5

13

For the purposes of this method that returns a list, just don't catch exceptions. Let it throw.

Unhandled exceptions in your application still need to be handled, but the error handling occurs much deeper in the call stack. Something closer to main() will essentially wrap the entire application in a try/catch block where it simply prints the message and stacktrace to the error output.

static int main(String[] args) {
    try {
        // CSV logic/application logic goes here
    return 0;
}
catch (Exception ex) {
    System.err.println(ex.toString());

    return 1;
}

}

This is a fairly consistent pattern across languages and tech stacks. Something closer to the start of the program catches everything and either logs the problem or prints it to the error output of the host OS. This detail is often hidden from us programmers by application frameworks, but it still exists. If your program doesn't catch the exception and handle it then the Java runtime needs to. And if the runtime cannot, then the host OS needs to, which should terminate the application. And if the host OS doesn't, then... I dunno. Reboot.

I'm just guessing, but since this is an example project for learning purposes, I imagine you don't have a full framework, which means you need to write the global error handling logic. When you don't see a better place, put it in main() or whatever function represents the start of a new thread, but keep the error handling logic simple. At that point you just need to report the problem for debugging purposes, especially for toy projects. If there is no way to recover and continue a use case, terminate the program.

In cases where retrying a use case is desirable, then you need to catch exceptions closer to the logic for that use case. For example, in the controller of an MVC application. This allows you to redraw the UI with an error message affording the user an opportunity to correct their input and try again.

13

Sometimes the best way to handle an exception is not at all.

Since I only want the error and stack trace to be printed in the console and the application to be terminated, what is the best approach to deal with this?

This looks like a job for a throws declaration. In Java, if you're throwing an (ick) checked exception out of the method then you need to say so in the method signature. FileReader throws a FileNotFoundException which is a checked exception.

public static List<Usuario> ler() throws FileNotFoundException {
    try (FileReader reader = new FileReader(UsuarioArquivo.getCaminho().toString())) {
        return new CsvToBeanBuilder<Usuario>(reader)
            .withType(Usuario.class)
            .build()
            .parse()
        ;
    }
}

Throwing from within a try-with-resources can get interesting but I believe this is all you need here.

This is not for a real application; it's just a simple study project, so if something goes wrong, I just want to know what happened and have the program terminate, nothing more.

Real or not, depending on how you're running the program, just letting the exception go uncaught may already do exactly that. Halting a program that is in an undefined state is a good thing. If you can't recover and put it back into a defined state then it's best to let it halt before it corrupts data, causes a security issue, or sends the president threating emails.

Now maybe you can recover. Either by rejecting the requested task or performing the task in some degraded way. Would your program react well if you simply returned an empty list?

I don't want to handle them in my application, mainly because I don't even know how to handle them.

Well that’s a bad reason to not handle them. Handle them wherever you can see what to do next. Something you were counting on didn’t work out. Can you see what to do next?

Easily 80% of code is just dealing with things going weird. Don’t be surprised if this takes a fair bit of work.

candied_orange
  • 119,268
5

Let the exceptions bubble up to your caller, by just adding a throws clause to the ler() method.

If someone calls your ler() method, it's important for them to know whether that was successful, meaning that the List returned here really represents the file contents in the way that was intended (that the method was able to fulfill its contract).

In most cases, this caller called ler() for some good reason, so with ler() failing it cannot complete its job in a meaningful way. So the caller again should signal its failure to its caller, and so on. That's what exceptions give you out-of-the-box (in Java, you need to declare the exception type in a throws clause).

Somewhere up the call stack, there might be a place where you can continue, even if something failed (e.g. a command loop in a console program, the main menu of a UI program, the services level of a web server, ...). There's the place where catching an exception makes sense. E.g. you want your server to continue processing new requests even if one of them couldn't be fullfilled.

Don't pay too much attention to the type of exception. The fact that you receive an exception tells you that some method failed. The type of exception gives you additional information, why it failed - that's nice for debugging, but your application logic should hardly ever try to analyze the failure reason.

5

Since I only want the error and stack trace to be printed in the console and the application to be terminated, what is the best approach to deal with this?

If you don't want to handle a checked exception and you don't want to have to add throws SomeCheckedException to every method signature up the stack, the simplest way to achieve that is to wrap your checked exception in an unchecked exception. E.g.:

try {
    // some stuff
} catch (SomeCheckedException e) {
    throw new SomeUncheckedException("a message if desired", e);
}
JimmyJames supports Canada
  • 30,578
  • 3
  • 59
  • 108
1

I think a good approach here would be to use a try-catch block in your method to print the stack trace and return null if an exception occurs

Something like this:

import com.opencsv.bean.CsvToBeanBuilder;
import java.io.FileReader;
import java.util.List;
import java.util.ArrayList;

public static List<Usuario> ler() { try (FileReader reader = new FileReader(UsuarioArquivo.getCaminho().toString())) { return new CsvToBeanBuilder<Usuario>(reader) .withType(Usuario.class) .build() .parse(); } catch (Exception e) { e.printStackTrace(); // Print the exception and stack trace to the console System.exit(1); // Terminates the program with a non-zero status } return new ArrayList<>(); // Added to satisfy compiler, although System.exit will terminate }