简体   繁体   中英

Exceptions as public classes vs. public static inner classes

I have two options (which technically are the same, as I understand) to declare a custom exception class thrown only from a particular class com.XXX.Foo :

  • as a public class in the package: com.XXX.CustomException
  • as a public static inner class: com.XXX.Foo.CustomException

Which option is better?

In case the exception is very specific to Foo class, I don't mind keeping it as a public Nested class. And whenever it seems like a time to extract that out, simply extract that out.

In general practice, I have never seen any nested class defined for Exception, though. I also don't know if one exist in Java API.

In my 10+ years experience with Java, I cannot recall coming across an API where a public exception class was defined as a static inner class. I cannot give you a specific reason why it would be a bad idea to do this, but it would certainly make your code unusual .

Why do you feel that it is necessary to do this, given that (apparently) nobody else does? I hope you are not just doing it to be "innovative".

(BTW, I know that some well-known Java APIs use public static inner classes and interfaces for other things. I'm specifically talking about the case of exception classes here.)

I can definitely think of situations where I'd prefer the exception to be a static inner class than merely a class in the same package.

The reasons not to do so seem to be:

  • Coupling the exception to the class that throws it makes it inappropriate to reuse in other contexts
  • Nobody else does it

I do not find either of those arguments at all convincing.

For the first point, why should this hypothetical future opportunity for re-use arise in the same package? This argument leads to the conclusion that we should put all exception classes as high as possible in the package hierarchy so that when we discover a future opportunity to reuse the same exception we don't have to introduce a dependency on where it was originally defined.

But even without the "taken to extremes" point, consider an exception intended to convey that class Foo was given wrong input. If I call it Foo.InvalidInput , the name is short and the association with Foo is impossible to miss. If I put it outside the Foo class and call it FooInvalidCriteria , then I can't reuse it from class Bar anyway, without changing its name (equivalent to changing its location).

But worst is if I leave it outside Foo and keep its name general like InvalidInput . Then when I later realise that Bar might have invalid input too and make it start throwing this exception. Everything compiles and runs fine, only now all the places that were catching InvalidInput and assuming they were handling errors from Foo could now also be handling errors from Bar if Foo happens to use Bar internally in a way that could cause this exception to be thrown. This could easily cause code breakage.

The reality is that taking an exception that was previously conceived as specifically indicating a situation that arises in one class and re-using it as a general error class is an interface change, not just an internal implementation change. To do so correctly in general you must revisit all the sites where the exception is caught and make sure they're still correct, so having the compiler tell you about all the use sites (because you have to change the name and/or import path) is a good thing. Any exception that you might make a static inner class is inappropriate for reuse in other contexts no matter whether you actually make it an inner class or not.

And as for the second dot point... "nobody else does it" never bears on anything. Either it really is the wrong thing to do, so there will be other reasons not to do it, so the "nobody else does it" argument is unnecessary. Or it isn't. And it's not like this particular example would even be terribly complicated and hard to understand, so not even the "it's unexpected so people will have trouble following it even if it's a good idea in theory" argument is very strong.

I'd prefer the (not necessarily public) class within the same package, as a package is a logical group of classes depicting a business model, which the exception belongs to as a technical part.

A user will see immediatelly that there's an exception when he looks at the package and does not need to read the file of class foo, which is better for maintenance and clarity/readability/comprehensional reasons. It's very good to define custom exceptions and to tell the API-user about it!

I'd only use an inner class when it's clearly a private thing of the class in question.

Nevertheless, we're talking here about a mainly conventional issue!

Exceptions as inner classes is a bad idea in general because by nature they may be raised through various levels, even in simple architectures. The exception class being raised must be referenced from its containing class, and if that class is unknown to the classpath something bad would probably happen like a ClassCastException.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM