简体   繁体   中英

What's the correct way to deal with Try/Catch Blocks and Errors in General when using multiple classes?

I'm trying to understand the correct structures of a program here to facilitate everything. Basically where to "put" things.

For example:

You have 2 classes.

Class 1 is your main.

Both classes have many methods.

Class 1 calls for an instance of Class 2 and runs a method. This method is supposed to return a value.

Question 1: Should I have a try/catch block INSIDE this method (in Class 2)?

Question 2: Should the try/catch block be where I call the method (in Class 1)?

try
   method();
catch
...

Question 3: When executing the method that is in Class 2, when it comes to returning a value, should I ever return "an error code" and then deal with this code in the calling class?

Question 4: When an error happens and I need to "halt" the program, should I use if/else statements so the code only moves forward if the correct conditions are met or should I use the keyword "break" more often?

Question 5: The possibilities for errors could be endless, specially if you have medium to large programs. How do you guys deal with unknowable errors which you might encounter while the user is running your program?

Exceptions are just that: exceptional. You shouldn't be using exceptions for regular program flow. (If you say, "Oh yeah, I expected that", it probably shouldn't be an exception.)

Handle the exception where it needs handling. If you can survive the function without that try-catch block succeeding, then you should handle it there. Similarly, if you need to wrap some things up, you can also add a finally block ( using is similar to finally in C#- it compiles down to try-finally , but is not as robust as writing it yourself. It simply calls .Dispose() on the disposable object you specified).

But if you need to bail out of that function, or you're running a string of functions that need to all succeed in your main class, it might be better to do the handling in your Class 1.

Caveat: There are exceptions (ha!) to every rule. As you program more, you can get an intuitive sense of where error handling should be done- but often there will be more than one option and it may not be clear cut.

In general, the answer to all those questions is "it depends". Clearly what you need to do depends on the specific circumstances of the situation and the application it contains.

From a practices point of view, I generally follow a couple rules:
1. Use exception handling instead of error codes
2. Only use try/catch when I know how to handle an exception

Clearly no one can tell you whether you need a try/catch within a method without knowing what that method does and whether or not you can handle any exceptions.

Whether or not an error code is really applicable is up to you. I generally view it as not applicable; but, sometimes it might be. In those cases I only view it as applicable if the caller will always use the code and not pass it on. "GetErrorCode" might be a good example of a case where an error code may be applicable.

You can't possibly "handle" (ie compensate for) "unknown" errors. The recommended practice is the not handle the exception and let the handle terminate gracefully because it's in an unknown state.

I in general agree w/ David and Peter... The one thing I would add is to be careful about exceptions you catch when you catch them... Richter has a very interesting chapter on exception handling and how exceptions were SUPPOSED to be inherited versus how they have actually been implemented... But even still, it's (IMO) lazy or at least ill-thought-out if you find yourself consistently catching the generic Exception class...

If you're doing file reading/writing, you may very well want to catch appropriate IO exceptions, but to consistently catch the most generic Exception class can lead you to problems if say, a NullReferenceException gets thrown and your try/catch was only protecting against IO Exceptions... Your catch block would try to fix (what it assumed was) an IO exception and it could put your code in a horribly unstable state.

Additionally, be very careful about continuing to re-throw the original error unless you're convinced you TRULY handled it appropriately... If you wrote a library and published it and swallowed all the errors because you thought you were doing the best thing, then someone that consumed your library would have no way to debug what was going on... Exceptions also get thrown into the servers logs, so a swallowed error would never make it there.

The one place that I would advocate catching the generic error is right at the UI layer where you obviously don't want to show the user a YSOD, but even then your catch should likely do some logging or something to help you debug later.

Catching exceptions and returning error codes/bools leads to "arrow" code like so:

if(Func1())
{
   if (Func2())
   {
       if (Func3())
       {
       }
   }
}

I unfortunately maintain a complex project where exceptions are treated like Ebola and are contained as soon as they sprout up. It really just makes the code harder to understand and maintain.

It depends on how you visualize and structure your application. Are classes 1 & 2 part of the same module or are they in different modules? In general, a module provides "API" and the caller of the "API" needs to catch errors and exceptions. Have a look at Defensive Programming .

Question 1: Should I have a try/catch block INSIDE this method (in Class 2)?

If Class 2 is a separate module and you do not want to propagate the exceptions to the caller module, then yes. If you want to, then no. The exceptions thrown from this Class/Module then need to be documented.

If Class 1 & 2 are in same module, then again it depends if you want to handle the exceptions within the internal classes or not.

Question 2: Should the try/catch block be where I call the method (in Class 1)?

If you want to safeguard to ensure Class 1 does not throw further exceptions, then yes.

Question 3: When executing the method that is in Class 2, when it comes to returning a value, should I ever return "an error code" and then deal with this code in the calling class?

If you want to throw exception of return an error code, is again a design/implementation decision.

Question 4: When an error happens and I need to "halt" the program, should I use if/else statements so the code only moves forward if the correct conditions are met or should I use the keyword "break" more often?

To use break you will need a loop in the caller.

Question 5: The possibilities for errors could be endless, specially if you have medium to large programs. How do you guys deal with unknowable errors which you might encounter while the user is running your program?

Large programs are divided into modules and could be coded by different developers. So the design and interface contract becomes essential here.

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