I'm having a little bit of trouble implementing the following method while handling the 3 exceptions I'm supposed to take care of. Should I include the try/catch blocks like I'm doing or is that to be left for the application instead of the class design?
The method says I'm supposed to implement this:
public Catalog loadCatalog(String filename)
throws FileNotFoundException, IOException, DataFormatException
This method loads the info from the archive specified in a catalog of products and returns the catalog.
It starts by opening the file for reading. Then it proceeds to read and process each line of the file.
The method String.startsWith is used to determine the type of line:
If the type of line is "Product", the method readProduct is called.
If the type of line is "Coffee", the method readCoffee is called.
If the type of line is "Brewer", the method readCoffeeBrewer is called.
After the line is processed, loadCatalog adds the product (product, coffee or brewer) to the catalog of products.
When all the lines of the file have been processed, loadCatalog returns the Catalog of products to the method that makes the call.
This method can throw the following exceptions:
FileNotFoundException — if the files specified does not exist.
IOException — If there is an error reading the info of the specified file.
DataFormatException — if a line has errors(the exception must include the line that has the wrong data)
Here is what I have so far:
public Catalog loadCatalog(String filename)
throws FileNotFoundException, IOException, DataFormatException{
String line = "";
try {
BufferedReader stdIn = new BufferedReader(new FileReader("catalog.dat"));
try {
BufferedReader input = new BufferedReader(
new FileReader(stdIn.readLine()));
while(! stdIn.ready()){
line = input.readLine();
if(line.startsWith("Product")){
try {
readProduct(line);
} catch(DataFormatException d){
d.getMessage();
}
} else if(line.startsWith("Coffee")){
try {
readCoffee(line);
} catch(DataFormatException d){
d.getMessage();
}
} else if(line.startsWith("Brewer")){
try {
readCoffeeBrewer(line);
} catch(DataFormatException d){
d.getMessage();
}
}
}
} catch (IOException io){
io.getMessage();
}
}catch (FileNotFoundException f) {
System.out.println(f.getMessage());
}
return null;
}
It depends on whether you want the class or another portion of the application that is using it to handle the exception and do whatever is required.
Since the code that will use the loadCatalog() probably won't know what to do with a file I/O or format exception, personally, I'd go with creating an exception like CatalogLoadException and throw it from within the loadCatalog() method, and put the cause exception (FileNotFoundException, IOException, DataFormatException) inside it while including an informative message depending on which exception was triggered.
try {
...
//do this for exceptions you are interested in.
} catch(Exception e) {
//maybe do some clean-up here.
throw new CatalogLoadException(e); // e is the cause.
}
This way your loadCatalog() method will only throw one single and meaningful exception.
Now the code that will use loadCatalog() will only have to deal with one exception: CatalogLoadException.
loadCatalog(String filename) throws CatalogLoadException
This also allows your method to hide its implementation details so you do not have to change its "exception throwing" signature when the underlying low level structure changes. Note that if you change this signature, every piece of code would need to change accordingly to deal with the new types of exceptions you have introduced.
See also this question on Exception Translation.
Update on the throwing signature requirement:
If you have to keep that signature then you don't really have a choice but to throw them to the application and not catch them inside the loadCatalog() method, otherwise the throws signature would be sort of useless, since we aren't going to throw the exact same exception that we have just dealt with.
The general idea is that you percolate exceptions up to the appropriate place to handle them. I am going to guess that your instructor expects them to be handled in main. In this case I can guess that because of the throws clause you were given. A simple rule of thumb is that if the method declares the exception in the throws clause you do not catch it in that method. So the method you are writing should have no catch statements.
To do that you would change your code something like:
public Catalog loadCatalog(String filename)
throws FileNotFoundException,
IOException,
DataFormatException
{
String line = "";
BufferedReader stdIn = new BufferedReader(new FileReader("catalog.dat"));
BufferedReader input = new BufferedReader(new FileReader(stdIn.readLine()));
while(!stdIn.ready())
{
line = input.readLine();
if(line.startsWith("Product"))
{
readProduct(line);
}
else if(line.startsWith("Coffee"))
{
readCoffee(line);
}
else if(line.startsWith("Brewer"))
{
readCoffeeBrewer(line);
}
}
return null;
}
and then in the method (presumably main) that calls loadCatalog you would have:
try
{
loadCatalog(...);
}
catch(FileNotFoundException ex)
{
ex.printStackTrace();
}
catch(IOException ex)
{
ex.printStackTrace();
}
catch(DataFormatException ex)
{
ex.printStackTrace();
}
replacing the printStackTrace with something appropriate.
That way the method, loadCatalog, doesn't deal with displaying the error messages, so you can call the method in GUI or console code and the code that calls it can choose how to display the error to the user (or deal with it in some way).
Here is an excellent article of Heinz Kabutz, dealing with exception handling.
http://www.javaspecialists.eu/archive/Issue162.html
Related
I want to make a test that reads from a file some data and passes that data to a function. That function calls other methods and some of them throw some exceptions. I'm interested in how can I check whether or not calling the method with the parameters from the file triggered an IOException somewhere along. I know that the code snippet provided will stop the execution because I've used assert. How should I write if I want to check if an IOException was thrown and if it was, to get the error message, without stopping the execution of the test? Thanks!
void test() throws IOException {
Service service = helperFunction();
File articles = new File("file.txt");
Scanner scanner = new Scanner(articles);
while(scanner.hasNextLine()) {
String line = scanner.nextLine();
line = line.replaceAll("[^\\d]", " ");
line = line.trim();
line = line.replaceAll(" +", " ");
String[] numberOnTheLine = line.split(" ");
List<Integer> list = Arrays.stream(numberOnTheLine).map(Integer::valueOf).collect(Collectors.toList());
Article article = new Article(Long.valueOf(list.get(0)),
new HashSet<>(List.of(new Version(list.get(1)))));
List<List<Article>> listOfArticles = Collections.singletonList(List.of(article));
Assertions.assertThrows(IOException.class,
() -> service.etlArticles(listOfArticles.stream().flatMap(List::stream).collect(Collectors.toList())));
}
}
Simple; a try/catch statement will take care of it.
Replace this:
service.etlArticles(listOfArticles.stream().flatMap(List::stream).collect(Collectors.toList())));
With:
try {
service.etlArticles(listOfArticles.stream().flatMap(List::stream).collect(Collectors.toList())));
} catch (IOException e) {
// Code jumps to here if an IOException occurs during the execution of anything in the try block
}
You are free to e.g. do some logging and then just Assert.fail, if you want.
assertThrows is quite simple, all it does is this:
try {
runThatCode();
} catch (Throwable e) {
if (e instanceof TypeThatShouldBeThrown) {
// Great, that means the code is working as designed, so, just...
return;
}
// If we get here, an exception was thrown, but it wasn't the right type.
// Let's just throw it, the test framework will register it as a fail.
throw e;
}
// If we get here, the exception was NOT thrown, and that's bad, so..
Assert.fail("Expected exception " + expected + " but didn't see it.");
}
Now that you know how it works, you can write it yourself and thus add or change or log or whatever you want to do during this process at the right place. However given you know it's IOException, instead of an instanceof check you can just catch (IOException e), simpler.
In GraphicsFileNotFoundException.java all I have is an import of FileNotFoundException and the class GraphicsFileNotFoundException which extends FileNotFoundException.
In my main java file, I'm trying to read in a graphics file with the method getGraphicsFile which throws GraphicsFileNotFoundException.
My brain is pooped after a good 40 minutes trying to find out how to catch this exception. I've tried using a try-catch block and catching GraphicsFileNotFoundException but I still get the error
unreported exception GraphicsFileNotFoundException ; must be caught
or declared to be thrown.
public void getGraphicsFile(String fileName) throws GraphicsFileNotFoundException {
String graphics = "";
Scanner getGraphics = null;
try {
getGraphics = new Scanner(new File(fileName));
}
catch (GraphicsFileNotFoundException e){
System.out.println("Error! File can't be found :/");
}
You need to either properly extend the FileNotFoundException class or manually throw an exception inside your try block.
Assuming this is for an assignment (I'm not sure why else you'd need to specifically extend this exception) you'll need to take another look at your GraphicsFileNotFoundException class and make sure that it does what it needs to.
To throw an exception, simply write your condition and the throw statement:
if(needToThrow) {
throw new GraphicsFileNotFoundException();
}
To catch an exception, surround the throw statement with a try block immediately followed by a catch block.
try {
// code here
if(needToThrow) {
throw new GraphicsFileNotFoundException();
}
}
catch(GraphicsFileNotFoundException e) {
// handle the error (print stack trace or error message for example)
e.printStackTrace(); // this is printing the stack trace
}
I recommend using Eclipse if you aren't already because many times it will offer to surround throw statements that need to be caught with a automatically generated try catch block.
I have a method that throws an Exception, which calls a method which throws an Exception, etc etc. So several methods that "throw Exception" are daisy-chained.
The first method that calls the submethod, puts that submethod in a try-catch block that catches any Exception that gets thrown inside that call. IN THEORY. In practice, no Exception is being caught by that try-catch block. Is there a way to remedy that?
Here is the code:
try {
CSVSingleton.tryToReadBothFiles(FILE1_PATH, FILE2_PATH);
} catch (Exception e) { // THIS BLOCK NEVER GETS ENTERED BY THE PATH O EXECUTION
System.out.println("There was an exception reading from at least one of the files. Exiting.");
System.exit(0);
}
here is the method from the CSVSingleton class:
public static void tryToReadBothFiles(String filePath1, String filePath2) throws Exception {
file1 = new CSVFileForDwellTime1(filePath1);
file2 = new CSVFileForDwellTime2(filePath2);
}
And here is code from the CSVFileForDwellTime1 class:
public CSVFileForDwellTime1(String filePath) throws Exception {
super(filePath);
}
and then here is the code that actually throws an original FileNotFoundException:
public GenericCSVFile(String filePath) throws Exception{
this.filePath = filePath;
try {
fileReader = new FileReader(filePath);
csvReader = new CSVReader(
fileReader);
header = getActualHeaderNames();
} catch (FileNotFoundException e) {
System.out.println("Could not read file with name: " + filePath);
// e.printStackTrace();
}
}
My guess is that the FileNotFoundException in the last method is caught by the catch block and so doesn't "bubble up". But is there a way to force it to bubble up?
Immediate answer:
Your thought is exactly right,
try {
fileReader = new FileReader(filePath);
csvReader = new CSVReader(
fileReader);
header = getActualHeaderNames();
} catch (FileNotFoundException e) {
System.out.println("Could not read file with name: " + filePath);
// e.printStackTrace();
}
This suppresses the exception
Either remove the try-catch block (desired unless you can actually do something with the exception)or re-throw it within the catch block.
Explanation
Generally with checked exceptions like this you have 2 options
Catch the exception and do something to remedy the exception
Throw the exception to the caller
What you have done here falls into the 1st category except that you have not done anything useful in the catch block (printing to console is rarely useful in this case because the exception message itself normally has enough information to see what has gone wrong)
The 2nd category is achieved either by not using a try-catch block and thus adding throws FileNotFoundException to the method signature. Alternatively explicitly throw the exception that you caught using:
catch(FileNotFoundException e)
{
//do something
throw e;
}
however in this case if do something isn't worthwhile you have unnecessarily caught something just to throw it on.
You can think of it like this:
Alice throws a ball to Charlie
Bob intercepts the ball
Bob then looks at the ball and then throws it to Charlie
Bonus Points
When you know the exception that could occur make sure to actually catch or throw that exception and not a parent of that exception.
Take the following method signatures for example:
public String method1() throws Exception
public String method2() throws FileNotFoundException
Here method2 clearly tells the caller what could happen and can help then figure out why the exception is being called (without having to read through the code or experience the error).
Secondly other exceptions can occur and you are potentially catching the wrong exception, take the following example:
try{
fileReader = new FileReader(filePath); //could potentially throw FileNotFoundException
fileReader = null; //woops
csvReader = new CSVReader(fileReader); //throws NullPointerException but the compiler will not know this
//....other stuff....//
}
catch(Exception e){
// the compiler told me that a FileNotFoundException can occur so i assume that is the reason the catch has executed
System.err.println("You have entered an invalid filename");
//doing anything here that would fix a FileNotFoundException is pointless because that is not the exception that occured
}
Use a throw in the catch clause.
} catch (FileNotFoundException e) {
System.out.println("Could not read file with name: " + filePath);
// Continue up, Mr. Exception!
throw e;
}
Alternatively, wrap the exception as appropriate (since an IOException is checked this handy here) - this is called a Chained Exception. Then, depending on what is thrown, the throws Exception can be removed from the method signature.
throw new RuntimeException("Could not read file: " + filePath, e);
If you don't want to catch it, then don't. Alternatively, you can just throw it again with a throw-statement. You can also throw a new Exception of any class you like. You should only catch an Exception at a level where you can react to it properly. As you found out, catching it at that low level is not helpful, so do not catch it there.
You can rethrow the exception once you catch it, for callees further up the stack to handle. You can change what exception it is too if a new type of exception makes more sense at a higher level.
catch (SomeSpecificException e)
{
some code here
throw new AMoreBroadException("I really need the callee to handle this too");
}
Technically you just need to add throw e right after System.out.println("Could not read file with name: " + filePath); and the exception will propagate up to the first method.
However, this would not be a clean way to handle the exception, because in this case all you'd be doing is printing an error message at the cost of changing the location of the original FileNotFoundException. Ideally, when you need to inspect an exception stacktrace, you expect a line of code throwing an exception to be the actual line that really caused the exception.
The throws Exception in the method declaration should be considered part of the contract of the method, i.e. it describes a possible behavior of the method. You should always ask yourself: Does it make sense for a FileNotFoundException to be specified as a possible exceptional behavior for the method/constructor I'm writing? In other words, do I want to make the caller of my method aware of this exception and leave it to the caller to deal with it? If the answer is yes (and in this case I would say it makes sense), then avoid wrapping the code in a try-catch block. If no, then your catch block should be responsible for dealing with the exception itself. In this specific example IMO there is not much you can do in the catch statement, so just remove the try-catch.
As mentioned by others, you should declare the most specific exception in the method signature (throws FileNotFoundException instead of throws Exception).
I'm currently working on an assignment (Java) for school. In the instructions/rubric, I'm told that I need to use I/O Exception Handling for command line arguments and other things.
**What The Program Needs to do: **
Take two command line arguments when it runs, or else throw an error.
The rubric includes this requirement : "I/O error handling is done if no command arguments"
The problem is, every time I try to use an I/O exception catch, I receive this error:
"Unreachable catch block for IOException. This exception is never thrown from the try statement body"
The quick fix suggestions I get from Eclipse:
1. Remove Catch clause
2. Replace Catch clause with close
Here is my Code:
import java.awt.Robot;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
public class DecipherText {
public static void main(String[] args) throws IOException {
String firstArg;
String secondArg;
if (args.length > 0) {
try {
firstArg = args[0];
secondArg = args[1];
} catch (IOException e) {
System.out.println("Usage Error: Not enough Arguments");
System.out.println(e);
return;
}
}
String inputFile = args[0];
String outputFile = args[1];
}
public static boolean receiver() {
return false;
}
public static boolean output() { // Outputs The Final File
return false;
}
}
My question(s) are:
If so, what am I doing wrong?
Is this requirement impossible/asking for the wrong usage of the I/O Error exception handling?
Any help is greatly appreciated.
Thanks,
Sully
I think the problem is that Java will never throw an IOException in the code
firstArg = args[0];
secondArg = args[1];
therefore, there is no need to catch an IOException. An exception you might catch could be ArrayIndexOutOfBoundsException if the user didn't provide 2 arguments.
IOException is sometimes thrown when you're communicating with outside sources such as through a Socket, or reading from a File and some reading of input goes wrong. But determining what's in the args array does not throw an IOException.
I'm not quite sure why your teacher specified I/O Exception. Does he mean input output in general or the Java IOException?
the reason its saying that is because there isn't any operation going on inside the try block that can possible throw IOException. in other words, there's no way you can get IOException from what's inside your try block. You can try catching ArrayIndexOutOfBoundsException since that can potentially happen in which case also remove the if(args.length > 0) as its no longer needed since you will be catching that error and handling it. Hope this helps.
You could use just this code in case theres no IOException, it will stop error, it just wont give an IO if there is one.
try {
} catch (Exception e) {
}
I cannot call this function although it does throw amnd handle IOException
public static String[] readtxt(String f) throws IOException{
try{
FileReader fileReader=new FileReader(f);
BufferedReader bufferedReader=new BufferedReader(fileReader);
List<String> lines=new ArrayList<String>();
String line=null;
while((line=bufferedReader.readLine())!=null)lines.add(line);
bufferedReader.close();
return lines.toArray(new String[lines.size()]);
}catch(IOException e){return null;}
}
...
private String[] truth=MainActivity.readtxt(file);
// ^ wont compile: Unhandled exception type IOException
You either need to handle the Exception your method is throwing like this
try{
private String[] truth = MainActivity.readtxt(file);
}catch(IOException ioe){
// Handle Exception
}
Or you can remove the throws clause from your method definition like this
public static String[] readtxt(String f) {
Looking at your code, I really doubt if the method will actually throw any IOException since you already caught. Therefore you can remove that clause.
But if you really want to throw that, then you can either remove the try-catch in your method or do something like this in your catch block
catch(IOException ioe){
// Throw IOE again
throw new IOException(ioe);
}
You define your method as throwing IOExceptions;
public static String[] readtxt(String f) throws IOException
This means that any method that calls this method must deal with such exceptions (in a catch block), you are not dealing with them in the method calling this method and so this error is raised.
However, you have handled any IOExceptions that might be thrown. It is not nessissary (or correct) to claim that the method could throw an IOException because it never will. Simply remove throws IOException.
You have handled the exception by returning null, this may or may not be correct depending on your implementation. On an IOException a null will be returned and the program will continue as if nothing happened, you may alternatively want to give an error message but as I say this depends on your exact circumstances
You need to handle the exception like below
try{
private String[] truth=MainActivity.readtxt(file);
}catch(IOException exception){
exception.printStackTrace()
}