1

I have made code to read text (json, xml etc.) from a text file, and convert it into a strings which can then be used by other code to convert into plain old java objects or POJOS that are annotated by jackson.

I am not sure if my code handles the exceptions properly. So far, I have used the principles mentioned after my code (READ THIS DOWN VOTERS !!!), to develop the code. Note that I cannot use try with resources because I am stuck with Java 6 (even though my project JRE is 1.8).

package com.testing;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class JunkEx {

    public static void main(String[] args) {
        String filePath = ".\\src\\test\\resources\\text-files\\orders\\orders-2017.txt";
        String contents = fileToString(filePath);
        System.out.println(contents);
    }

    private static String fileToString(String filePath) {
        StringBuilder stringBuilder = null;
        BufferedReader br = null;

        try {
        br = new BufferedReader(new FileReader(filePath));
        stringBuilder = new StringBuilder();
        String currentLine;
        while ((currentLine = br.readLine()) != null) {
            stringBuilder.append(currentLine);
            stringBuilder.append("\n");
        }

        }catch (FileNotFoundException ex1) {
            ex1.printStackTrace();
        }catch (IOException ex2) {
            ex2.printStackTrace();
        }finally {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return stringBuilder.toString();
    }

}

Principles:

1) Catch the most specific exception first, then the one above it in the exception hierarchy. I.e catch FileNotFoundException 1st and IOException later. Refer point 5 here

2) Do NOT return from inside a finally block, because finally is always executed as long as try "completes" fully or abruptly. Refer this SO answer.

3) Cleanup resources like buffered readers in the finally block. Refer point 1 here.

4) Do not make the callers of the "dangerous" method (i.e. which could throw exceptions), have to know/throw each of the exceptions inside it. I.e dangerous method should not "throws FileNotFoundException, IOException...etc". refer this link, specifically the last paragraph

Flaw in the code: If any of the first two catch blocks are executed, then its likely that the entire file was not read. But, my method will return a string anyway. The string could be null or incomplete.

Questions -

1) I want to throw an exception when the text file is not successfully converted to a string, i.e. one of the three catch blocks is executed. Should I wrap the exception in each catch block inside a generic Exception object and throw that or do something else ?

2) How can I improve/fix the exception handling of this code?

Project structure: enter image description here

MasterJoe
  • 2,103
  • 5
  • 32
  • 58
  • Please mention why I got negative votes. I put effort into reading and finding out how to make my code. All I am requesting for is hints or directions to fix/improve it. How could I improve this question ? – MasterJoe Dec 05 '17 at 06:01

2 Answers2

2

Simple answer: don't catch the exceptions at all. Let the caller catch them. He's the one who needs to know, and knows what to do about them. This method certainly doesn't.

4) Do not make the callers of the "dangerous" method (i.e. which could throw exceptions), have to know/throw each of the exceptions inside it. I.e dangerous method should not "throws FileNotFoundException, IOException...etc". refer this link, specifically the last paragraph.

I don't think much of this 'principle', and in any case it doesn't actually apply here. The only exceptions thrown are IOException and FileNotFoundException, which is derived from it. The caller doesn't have to deal with both if he doesn't wish to. However he may wish to do exactly that, if for example the file being missing constitutes a deployment error.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I want to make these error messages friendly as well. I wrapped all the exceptions inside an IOException like this - throw new IOException("Erorr: What happened here : ", exception); Now the caller has to only catch IOException. Is this good enough ? – MasterJoe Dec 05 '17 at 06:33
  • 1
    No. It's better for the caller to deal with the exception completely. He's the one who wanted to read the file, he's the one who knows what the application function is at this point, and what the file is actually for, and has a better idea of what the error message should say. Also, he only needs to catch `IOException`, so the burden isn't quite what you're making out. Catch-log-throw is frequently considered poor practice. You should at least *log* the original exception, even if you display a different message to the user. It's preferable to display the exception's own message if possible. – user207421 Dec 05 '17 at 06:50
  • 1
    I was going to say exactly this as soon as I read your principle #4. It's just wrong. If you don't know exactly how to deal with an exception, just pass it to the higher level layer. If you do know how to deal with the exception, you shouldn't need "principles" to tell you what to do. Normally the highest level layer shows the user an error dialog or logs the error and silently fails. But if you don't know what's expected, don't try to hide the error: send the problem to the layer that knows by throwing it. – markspace Dec 05 '17 at 07:19
  • @EJP - FYI, Looks like there is a bug in this page. My upvote of your answer increased your score to two. When I accidentally clicked downvote on your answer, it made your score zero. I refreshed my firefox browser and the problem still happens. – MasterJoe Dec 05 '17 at 17:16
1

You have two options:

  1. Don't catch the exceptions and let the caller deal with them
  2. Catch the exceptions and throw your own custom exception, say FileToStringFailedException, that wraps the actual exception. The wrapping part is extremely important, so that when someone up the call chain does a printStackTrace() you get a Caused By section that explains the real failure.

Either option works, and which one you choose depends on the overall design. For something simple I'd just let the exceptions percolate upwards; if I was designing a large complex library with other custom wrapper exceptions I might choose option 2.

Without a lot more context about what you're doing and where this fits into your system, it's not possible to say one option is "better".

Whatever you do, NEVER interfere with the actual exception. Exceptions are for programmers, not users. If you want "friendly" errors for users, do that at the point where the exceptions are displayed to the users, but make sure the original exceptions are logged for the programmers. otherwise you will regret it severely when your "friendly" exception hides crucial information that you need to troubleshoot a problem.

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
  • I have made code to read text (json, xml etc.) from a text file, and convert it into a strings which can then be used by other code to convert into plain old java objects or POJOS that are annotated by jackson. – MasterJoe Dec 05 '17 at 06:58
  • I want to make these error messages friendly as well. I was wondering if its a good idea to wrap all the exceptions inside IOException, like this - throw new IOException("Erorr: What happened here", exception); Now the caller has to only catch IOException. Is this wrapping ok/advisable ? – MasterJoe Dec 05 '17 at 07:00
  • I just noticed that if the first line in try does not even run due to an exception such as FileNotFound, then the stringBuilder will be null and the calling code will throw a null pointer exception. The user of the function will never know what really caused the problem. :( – MasterJoe Dec 05 '17 at 07:15
  • 1
    Which reinforces the point that this method *must* throw an exception somehow. – user207421 Dec 05 '17 at 07:18