34

I have this factory method in java:

public static Properties getConfigFactory() throws ClassNotFoundException, IOException {
    if (config == null) {
        InputStream in = Class.forName(PACKAGE_NAME).getResourceAsStream(CONFIG_PROP);
        config = new Properties();
        config.load(in);
    }
    return config;
}

And I want to transform the two checked exceptions into unchecked exceptions. What is the best way to go about this?

Should I just catch the exception and throw a new RuntimeException using the caught exception as the inner exception?

Is there a better way to do this or should I even be attempting to do this in the first place?

EDIT:
Just to clarify. These exceptions will be fatal, as the configuration file is essentially to the operation of the program and all exception will be caught and logged at the top level of my program.

My purpose is to avoid an unnecessary throws exception, exception added to the signature of every method that calls my factory.

Josh Lee
  • 171,072
  • 38
  • 269
  • 275
James McMahon
  • 48,506
  • 64
  • 207
  • 283
  • What is your purpose for doing it in the first place? Why not let the method caller decide what to do with the exceptions? – DMKing Jan 27 '09 at 19:21
  • 2
    Well the idea behind my factory is to avoid excessive amounts of code. I would rather not have to have a try catch block whenever I use it. – James McMahon Jan 27 '09 at 19:23
  • You can write a helper function to convert thrown exceptions to unchecked ones. Essentially you would call something like `callUnchecked(() -> getConfigFactory())` in your code and define `callUnchecked` similar to `try { return supplier.get(); } catch (Throwable ex) { throw new RuntimeException(ex); }`. This way you state explicit in the caller code that the call might fail and cause a crash, but you do not bloat the code too much. Obviously, this is Java 8 only because of the lambda. – Qw3ry Sep 21 '17 at 13:55

4 Answers4

41

A RuntimeException should be used only when the client cannot recover from whatever the problem is. It is occasionally appropriate to do what you are talking about, but more often it is not appropriate.

If you are using a JDK >= 1.4, then you can do something like:

try {
  // Code that might throw an exception
} catch (IOException e) {
  throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
  throw new RuntimeException(e);
}

and the rethrown RuntimeException will have the original cause included inside it. This way, someone at the top of the thread catching the RuntimeException -- your threads do catch RuntimeException so they don't just silently die, right? -- can at least print out the FULL stack trace of the cause.

But as others have said and will say, exceptions are checked for a reason. Only do this when you are positive that your clients cannot recover from the problem that you are rethrowing as an unchecked exception.

NOTE: Better than just RuntimeException would be to use a more specific unchecked exception if one is available. For example, if the only reason your method could throw a ClassNotFoundException is because a configuration file is missing, you could rethrow a MissingResourceException, which is an unchecked exception but gives more information about why you are throwing it. Other good RuntimeExceptions to use if they describe the problem you are rethrowing are IllegalStateException, TypeNotPresentException and UnsupportedOperationException.

Also note that it is ALWAYS a good idea for your threads to catch RuntimeException and at a minimum log it. At least this way you understand why your threads are going away.

Eddie
  • 53,828
  • 22
  • 125
  • 145
  • Even better, extends RuntimeException. – Loki Jan 27 '09 at 19:29
  • 4
    I prefer to keep my exceptions generic and stay away from custom ones, where possible. – James McMahon Jan 27 '09 at 19:42
  • 4
    It's OK to stay away from custom exceptions, which is why I mentioned several of the most useful RuntimeExceptions that already exist as part of Java. A more specific Exception really helps during debugging. – Eddie Jan 27 '09 at 19:48
  • MissingResourceException seems like the way to go, unfortunately it lacks a constructor to just simply pass another exception into it. – James McMahon Jan 27 '09 at 20:27
  • 1
    Then you have to say: m = new MissingResourceException(); m.initCause(e); throw m; – Adrian Pronk Jan 27 '09 at 20:39
  • 3
    Ah java. Is there anything you can't make unnecessarily verbose? – James McMahon Jan 27 '09 at 21:09
  • @JamesMcMahon: I consider it unfortunate that there isn't a nice way of saying "Any FooException thrown *from a method called within this block of code* should be considered unexpected, and wrapped in a `BarException`". Even (*especially!*) if the block of code performs a `throw new FooException()` itself, a `FooException` thrown within a nested method may imply a state which won't match the expectations of calling code that would catch `FooException`. – supercat Jan 13 '14 at 23:16
  • @AdrianPronk - there is no constructor `MissingResourceException()' in JDK 8 – JimHawkins Feb 06 '17 at 13:19
  • @JimHawkins: I already knew that but thanks for pointing it out. As you probably guessed, the parameters that need to be passed to the constructor are an irrelevant distraction to the point I was trying to make in my comment, so I omitted them. I tend not to bother whether my code examples will actually compile and aim instead to illustrate some principle. – Adrian Pronk Feb 06 '17 at 21:19
15

Two points regarding exception handling best practices:

  • Caller code cannot do anything about the exception -> Make it an unchecked exception
  • Caller code will take some useful recovery action based on information in exception -> Make it a checked exception

And you may throw the RuntimeException with or without inner exception, depending on what the caller can do with it. If you're not rethrowing the inner exception then you should log it in your method, if important.

MicSim
  • 26,265
  • 16
  • 90
  • 133
4

You are doing it the correct way.

In order to let checked exceptions pass though without being checked, you must wrap them in un-checked exceptions.

Just remember, Exceptions are checked for a reason.

jjnguy
  • 136,852
  • 53
  • 295
  • 323
  • The checked Exceptions are an abomination.Some disadvantages. Viral to caller code (just add new exceptions to throws and get yourself ready for a huge refactor and secondly anyway the caller has to prepare for unchecked exceptions, java 8 functional api does not like checked exceptions. – mhstnsc Oct 17 '16 at 15:03
  • @mhstnsc, "viral" is an advantage. This is akin to changing a return type. It should break the caller code. The caller code conforms to a contract that no longer exists. – Vsevolod Golovanov Mar 16 '17 at 11:10
  • 1
    @VsevolodGolovanov Yes, but this contract is completely void by RuntimeExceptions. I agree with you if there would be no RuntimeExceptions. RuntimeExceptions are a patch to exactly correct this viral problem. They probably had huge backward compatibility problems just because they wanted to add a new exceptional flow in the implementation. If you manage your own code thats easy but if you break your code in backward compatible layers you will soon learn to hate it as much as i do :) – mhstnsc Jun 20 '17 at 12:07
1

If you want to avoid too many try - catches, catch both the exceptions in the factory itself and handle them there. Perhaps return a default implementation.

You have to handle the exceptions, here or somewhere else.

And since this is a factory, I think it is better that these exceptions are handled in the factory itself (same method or different method), and returning a default implementation.

Anyway, the (business function) caller will have no clue on what has to be done when it encounters a ClassNotFoundException.

Nivas
  • 18,126
  • 4
  • 62
  • 76