Suppose we are writing a Java library, which provides some I/O ulitity functions, for example, a convenient method to read text files as Strings:
public class StringReader {
private static final Logger log = LoggerFactory.getLog(StringReader.class);
/**
* Returns the contents of file <b>fileName</b> as String.
* @param fileName file name to read
* @return null on IO error
*/
public static String readString(String fileName) {
FileInputStream fis = null;
try {
fis = new FileInputStream(fileName);
byte[] data = new byte[fis.available()];
fis.read(data);
return new String(data, "ISO-8859-1"); // may throw UnsupportedEncodingException!
} catch (IOException e) {
log.error("unable to read file", e);
} catch (UnsupportedEncodingException e) {
log.fatal("JRE does not support ISO-8859-1!", e);
// ???
} finally {
closeQuiet(fis);
}
return null;
}
}
This code reads a text file into a String using ISO-8859-1 encoding and returns the String to user.
The String(byte[], String)
constructor throws an UnsupportedEncodingException
when specified encoding is not supported. But, as we know, ISO-8859-1
must be supported by JRE, as said here (see the Standard charsets section).
Hence, we expect the block
catch (UnsupportedEncodingException e) {
log.fatal("encoding is unsupported", e);
// ???
}
is never reached if JRE distribution conforms the standard.
But what if it doesn't? How to handle this exception in the most correct way? The question is, how to alert properly about such error?
The suggestions are:
RuntimeException
.assert false
here, so it produce AssertionError if user launched VM with -ea
.AssertionError
manually.UnsupportedEncodingException
in method declaration and allow user to choose. Not very convenient, I think.System.exit(1)
.Thanks.
Fatal errors are errors such as native memory exhaustion, memory access errors, or explicit signals directed to the process.
As I've noted in another place, you can create a fatal error via: if($isTestMode==1){ eval("noSuchFunction();"); } This method will always work.
Throwing an exception is as simple as using the "throw" statement. You then specify the Exception object you wish to throw. Every Exception includes a message which is a human-readable error description. It can often be related to problems with user input, server, backend, etc.
You can just specify throws Exception for the main method to let the console receive the stack traces. So in the end: use throws in the signature of your methods instead of catching exceptions before you want to handle them. Save this answer.
But what if it doesn't?
Then you're in a really bad situation, and you should probably get out of it as quickly as possible. When a JRE is violating its own promises, what would you want to depend on?
I'd feel happy using AssertionError
in this case.
It's important to note that not all unchecked exceptions are treated equally - it's not unusual for code to catch Exception
at the top level of the stack, log an error and then keep going... if you just throw RuntimeException
, that will be caught by such a scheme. AssertionError
would only be caught if the catch block specified Throwable
(or specifically Error
or AssertionError
, but that's much rarer to see). Given how impossible this should be, I think it's reasonable to abort really hard.
Also note that in Java 7, you can use StandardCharsets.ISO_8859_1
instead of the string name, which is cleaner and removes the problem.
There are other things I'd change about your code, by the way:
available()
as far as possible. That tells you how many bytes are available right now - it doesn't tell you how long the file is, necessarily.read()
will read the whole file in one go. Call read()
in a loop, ideally until it says there's no more data.Charset
as a parameter, rather than hard-coding ISO-8859-1. - I would let IOException
bubble up from the method rather than just returning null
. After all, unless you're really going to check the return value of every call for nullity, you're just going to end up with a NullPointerException
instead, which is harder to diagnose than the original IOException
.Alternatively, just use Guava's Files.toString(File, Charset)
to start with :) (If you're not already using Guava, now is a good time to start...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With