Use exceptions rather than return codes: unused value - exception

In the clean code book is an example about using exceptions rather than return codes:
You either set an error flag or returned an error code.
public class DeviceController {
...
public void sendShutDown() {
DeviceHandle handle = getHandle(DEV1);
// Check the state of the device
if (handle != DeviceHandle.INVALID) {
// Save the device status to the record field
retrieveDeviceRecord(handle);
// If not suspended, shut down
if (record.getStatus() != DEVICE_SUSPENDED) {
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDevice(handle);
} else {
logger.log("Device suspended. Unable to shut down");
}
} else {
logger.log("Invalid handle for: " + DEV1.toString());
}
}
...
}
Unfortunately, it's easy to forget. For this reason, it is better to throw an exception when you encounter an error. The calling code is cleaner. Its logic is not obscured by error handling.
public class DeviceController {
...
public void sendShutDown() {
try {
tryToShutDown();
} catch (DeviceShutDownError e) {
logger.log(e);
}
}
private void tryToShutDown() throws DeviceShutDownError {
DeviceHandle handle = getHandle(DEV1);
DeviceRecord record = retrieveDeviceRecord(handle);
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDevice(handle);
}
private DeviceHandle getHandle(DeviceID id) {
...
throw new DeviceShutDownError("Invalid handle for: " + id.toString());
...
}
...
}
The code is better because two concerns that were tangled, the algorithm for device shutdown and error handling, are now separated. You can look at each of those concerns and understand them independently.
Now my question is not so much about the whether to use exceptions or return codes but I am wondering about the unused DeviceRecord in the second "good example", which uses exceptions.
Wouldn't it be enough to just call retrieveDeviceRecord(handle); to save the device status to the record field as in the "bad example code" but change the method to also throw an exception in case anything goes wrong during retrieveDeviceRecord(handle);? Or is there a purpose of returning DeviceRecord but not using it?

Related

What is the purpose of multiple "catch" blocks in exception handling

Why we need multiple "catch" blocks even though we can write one generic
exception?
Is that important to know all the exception types and their purposes to make a good piece of code?
I googled a lot but still have confusions in exception handling. Any good example?
Generic Exception:
try{
//some code
}
catch(Exception e){
//print e
}
//that's it.
Multiple catches
try{
//some code
}
catch(IOException e){
}
catch(SQLException e){
}
There are several advantages of using multiple exceptions:
General exceptions will not let you know the exact root cause of the issue especially if many steps/checks involved in a method implementation. Also, If the exception occurs due to various reasons, you need to throw the different types of exceptions from your caller method implementation.
Eg: You can throw custom exceptions.
Here is your service code:
public void Login(string username, string password)
{
if(string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
{
throw InvalidUserNameException();
}
if(!IsInternetAvaialable())
{
throw NoInternetAvailableException()
}
else
{
//Implement though your login process and if need use various custom exceptions or throw the exception if occurs.
}
}
public class InvalidUserNameException : Exception
{
public InvalidUserNameException()
{
}
public InvalidUserNameException(string message)
: base(message)
{
}
public InvalidUserNameException(string message, Exception inner)
: base(message, inner)
{
}
}
Caller Method:
try {
...
} catch(InvalidUserNameException e) {
// Show Alert Message here
} catch(NoInternetAvaibleException e) {
// Show Alert Message with specific reason
}
catch(Exception e) {
// Other Generic Exception goes here
}
Reference:
https://learn.microsoft.com/en-us/dotnet/standard/exceptions/how-to-create-user-defined-exceptions
1. Why we need multiple "catch" blocks even though we can write one generic exception?
Sometimes you might need to specify what causes the problem.
For example,
try {
...
} catch(IOException e) {
// Print "Error: we cannot open your file"
} catch(SQLException e) {
// Print: "Error: we cannot connect to the database"
}
With different errors, users can understand what went wrong easily.
If we go with
try {
...
} catch(Exception e) {
// Print "Error: " + e.
}
It's harder for the users to figure out what went wrong.
Also, we can send the users to different pages accordingly to the error if we use multiple catch-es.
2.Is that important to know all the exception types and their purposes to make a good piece of code?
Personally, I would go with important exceptions such as IO, DB, etc. that can cause serious trouble. For others, I would catch with general exception.

Handling Runtime Exception in CompletableFuture in java8

Below is the sample code I'm using to understand exception handling in completablefuture in java8.
If we make use of exceptionally method as per doc,
exceptionally method catches even runtime exception as well and proceeds to last block in the pipeline.
if we don't use exceptionally method then, it justs prints running and exits.
Correct me if my understanding isn't correct.
Question is Lets say if i want to throw runtime exception and want application to stop. Basically if i throw Runtime exception , it shouldn't proceed to next block in pipeline. How should i do that. Any pointers are helpful.
public static void main(String[] args) {
final CompletableFuture<String> retrieveName = CompletableFuture.supplyAsync(() -> {
System.out.println("running");
int i = 0;
if(i == 0) {
throw new RuntimeException("ding");
}
return "test";
}).exceptionally(it -> {
System.out.println(it.getMessage());
return "empty";
}).thenApply(it -> {
System.out.println("last block" + it);
return "dummy";
});
}
Try this:
public static void main(String[] args) {
try {
final CompletableFuture<String> retrieveName = CompletableFuture.supplyAsync(() -> {
System.out.println("running");
int i = 0;
if (i == 0) {
throw new RuntimeException("ding");
}
return "test";
}).exceptionally(it -> {
if (it.getMessage().contains("ding")) {
throw (RuntimeException) it;
}
System.out.println(it.getMessage());
return "empty";
}).thenApply(it -> {
System.out.println("last block" + it);
return "dummy";
});
retrieveName.join();
} catch (Exception e) {
System.out.println("main() exception, cause=" + e.getCause());
}
}
This is the output:
running
main() exception, cause=java.lang.RuntimeException: ding
I made 3 small changes to your code:
Wrapped it all in a try-catch
Threw a RuntimeException in exceptionally() for the "ding" exception.
Added a call to retrieveName.join(). From the Javadoc for CompletableFuture.join():
public T join​()
Returns the result value when complete, or throws an (unchecked) exception if completed exceptionally.
Update based on OP feedback ------->
Lets say if i want to throw runtime exception and want application to
stop. Basically if i throw Runtime exception , it shouldn't proceed to
next block in pipeline. How should i do that.
You can achieve what you want with just 2 changes to your code:
[1] Completely remove the exceptionally() callback so the CompletableFuture (CF) terminates with an exception. In exceptionally() in the OP code the exception was being swallowed rather than rethrown, and returning a CF, so the thenApply() method was still performed.
[2] Add a call to retrieveName.join() at the end of main(). This is a blocking call, but since the thread had terminated with an exception that 's not really relevant for the sample code. The join() method will extract the thrown RunTimeException and re-throw it, wrapped in a CompletionException.
Here's your modified code:
public static void main(String[] args) {
final CompletableFuture<String> retrieveName = CompletableFuture.supplyAsync(() -> {
System.out.println("running");
int i = 0;
if(i == 0) {
throw new RuntimeException("ding");
}
return "test";
}).thenApply(it -> {
System.out.println("last block" + it);
return "dummy";
});
retrieveName.join();
}
Notes:
This is not how to do things in Production. The blocking call from join() was not a problem here, but could be for a long running CF. But you obviously can't extract the exception from the CF until it is complete, so it makes sense that the join() call blocks.
Always bear in mind that main() is not running in the same thread(s) as the CF.
An alternative approach (if viable) might be to handle all the necessary post-exception actions (logging, etc,) within exceptionally() and then terminate normally with a suitable return value (e.g. "Exception handled!") rather than propagating the exception.
You can check whether the CF is still running by calling the non-blocking isDone() method. You can also check whether the CF ended with an exception (isCompletedExceptionally()) or was cancelled(isCancelled​()).

Submitting score to GameCenter using RoboVM and libgdx

I am using libgdx and robovm.
I get an error when I try to submit the score to the leaderboard on GameCenter on iOS. I am able to show the leaderboard. This is the error I get:
*** Terminating app due to uncaught exception 'GKInvalidArgumentException', reason: 'A GKScore must specify a leaderboard.'
libc++abi.dylib: terminating with uncaught exception of type NSException
It is similar to this SO-post, but it is objective-c so I dont understand the answer.
This is my code for showing the leaderboard (this works)
public void getLeaderboardGPGS() {
// If player is not authenticated, do nothing
if (!GKLocalPlayer.getLocalPlayer().isAuthenticated()) {
return;
}
GKGameCenterViewController gameCenterView = new GKGameCenterViewController();
gameCenterView.setGameCenterDelegate(new GKGameCenterControllerDelegateAdapter() {
#Override
public void didFinish (GKGameCenterViewController gameCenterViewController) {
dismissViewControllerAndNotifyListener(gameCenterViewController, GKGameCenterViewControllerState.Leaderboards);
}
});
gameCenterView.setViewState(GKGameCenterViewControllerState.Leaderboards);
gameCenterView.setLeaderboardIdentifier(identifier);
keyWindow.getRootViewController().presentViewController(gameCenterView, true, null);
}
This is my code for submiting the score (this does not work)
public void submitScoreGPGS(int score, MyLeaderBoardCallback callback) {
// If player is not authenticated, do nothing
if (!GKLocalPlayer.getLocalPlayer().isAuthenticated()) {
//listener.scoreReportFailed(buildUnauthenticatedPlayerError());
Gdx.app.log("Gamecenter","Notlogedin");
return;
}
GKScore scoreReporter = new GKScore(identifier);
scoreReporter.setValue(score);
scoreReporter.setLeaderboardIdentifier(identifier);
//scoreReporter.setShouldSetDefaultLeaderboard(true);
//scoreReporter.setContext(0);
NSArray<GKScore> scores = new NSArray<GKScore>(scoreReporter);
Gdx.app.log("Gamecenter","Report socre");
GKScore.reportScores(scores, new VoidBlock1<NSError>() {
#Override
public void invoke (NSError error) {
if (error != null) {
Gdx.app.log("Gamecenter","scorereportfailed");
} else {
Gdx.app.log("Gamecenter","scorereportcompleted");
}
}
});
}
Anyone knows what the problem might be? I have tried googleing but there is little information about "robovm and gamekit/gamecenter".
The variable that contained the leaderboard id was garbage collected for some reason. Had to hard-code the string at scoreReporter.setLeaderboardIdentifier("my hard coded id"); . Weird....

How should I handle exceptions within a controller constructor in WebAPI?

Say I have a constructor where it's initialization can potentially throw an exception due to reasons beyond my control.
FantasticApiController(IAwesomeGenerator awesome,
IBusinessRepository repository, IIceCreamFactory factory)
{
Awesome = awesome;
Repository = repository;
IceCream = factory.MakeIceCream();
DoSomeInitialization(); // this can throw an exception
}
Ordinarily, when a Controller action in WebAPI throws an exception I can handle it via a csutom ExceptionFilterAttribute:
public class CustomErrorHandler
{
public override void OnException(HttpActionExecutedContext context)
{
// Critical error, this is real bad.
if (context.Exception is BubonicPlagueException)
{
Log.Error(context.Exception, "CLOSE EVERYTHING!");
Madagascar.ShutdownAllPorts();
}
// No big deal, just show something user friendly
throw new HttpResponseException(new HttpResponseMessage
{
Content = new StringContent("Hey something bad happened. " +
"Not closing the ports though"),
StatusCode = HttpStatusCode.InternalServerError;
});
}
So if I have a have a BoardPlane API method which throws a BubonicPlagueException, then my CustomerErrorHandler will shut down the ports to Madagascar and log it as an error as expected. In other instances when it's not really serious, I just display some user friendly message and return a 500 InternalServerError.
But in those cases where DoSomeInitialization throws an exception, this does absolutely nothing. How can I handle exceptions in WebAPI controller constructors?
The WebApi Controllers are created, and thus constructors called via HttpControllerActivators. The default activator is System.Web.Http.Dispatcher.DefaultHttpControllerActivator.
Very rough examples for options 1 & 2 on github here https://github.com/markyjones/StackOverflow/tree/master/ControllerExceptionHandling/src
Option 1 which works quite nicely involves the use of a DI container (you may well be using one already). I have used Ninject for my example and have used "Interceptors" Read More to intercept and try/catch calls to the Create method on the DefaultHttpControllerActivator. I know of at least AutoFac and Ninject that can do something simlar to to the following:
Create the interceptor
I don't know what the lifetime scope of your Madagascar and Log items are but they could well be injected into your Interceptor
public class ControllerCreationInterceptor : Ninject.Extensions.Interception.IInterceptor
{
private ILog _log;
private IMadagascar _madagascar;
public ControllerCreationInterceptor(ILog log, IMadagascar madagascar)
{
_log = log;
_madagascar = madagascar;
}
But keeping to the example in your question where Log and Madagascar are some kind of Static global
public class ControllerCreationInterceptor : Ninject.Extensions.Interception.IInterceptor
{
public void Intercept(Ninject.Extensions.Interception.IInvocation invocation)
{
try
{
invocation.Proceed();
}
catch(InvalidOperationException e)
{
if (e.InnerException is BubonicPlagueException)
{
Log.Error(e.InnerException, "CLOSE EVERYTHING!");
Madagascar.ShutdownAllPorts();
//DO SOMETHING WITH THE ORIGIONAL ERROR!
}
//DO SOMETHING WITH THE ORIGIONAL ERROR!
}
}
}
FINALLY Register the interceptor In global asax or App_Start (NinjectWebCommon)
kernel.Bind<System.Web.Http.Dispatcher.IHttpControllerActivator>()
.To<System.Web.Http.Dispatcher.DefaultHttpControllerActivator>().Intercept().With<ControllerCreationInterceptor>();
Option 2 is to implement your own Controller Activator implementing the IHttpControllerActivator interface and handle the error in creation of the Controller in the Create method. You could use the decorator pattern to wrap the DefaultHttpControllerActivator:
public class YourCustomControllerActivator : IHttpControllerActivator
{
private readonly IHttpControllerActivator _default = new DefaultHttpControllerActivator();
public YourCustomControllerActivator()
{
}
public System.Web.Http.Controllers.IHttpController Create(System.Net.Http.HttpRequestMessage request, System.Web.Http.Controllers.HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
try
{
return _default.Create(request, controllerDescriptor, controllerType);
}
catch (InvalidOperationException e)
{
if (e.InnerException is BubonicPlagueException)
{
Log.Error(e.InnerException, "CLOSE EVERYTHING!");
Madagascar.ShutdownAllPorts();
//DO SOMETHING WITH THE ORIGIONAL ERROR!
}
//DO SOMETHING WITH THE ORIGIONAL ERROR!
return null;
}
}
}
Once you have your own custom activator the default activator can be switched out in the global asax :
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new YourCustomControllerActivator());
Option 3 Of course if your initialisation in the constructor doesn't need access to the actual Controllers methods, properties etc... i.e. assuming it could be removed from the constructor... then it would be far easier to just move the initialisation to a filter e.g.
public class MadagascarFilter : AbstractActionFilter
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
try{
DoSomeInitialization(); // this can throw an exception
}
catch(BubonicPlagueException e){
Log.Error(e, "CLOSE EVERYTHING!");
Madagascar.ShutdownAllPorts();
//DO SOMETHING WITH THE ERROR
}
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
{
base.OnActionExecuted(actionExecutedContext);
}
public override bool AllowMultiple
{
get { return false; }
}
}

Retry after Spring throws DataAccessException not working

I am facing a very peculiar situation. I am using hibernate template with spring 3.0.5 for DB operations. When I try to insert a User model the first time, a DataAccessException is thrown, which I catch. Now I wish to retry the same DB operation for say 3 times. The second time when it, no exception is thrown.
Here is the code:
package com.user.profile.dao;
#Repository("userProfileDAOImpl")
public class UserProfileDAOImpl implements IUserProfileDAO {
#Autowired
private HibernateTemplate hibernateTemplate;
public Long insertUserProfileData(User user) throws AppNonFatalException {
Long id = null;
int retryCount = 0;
while (retryCount < 3) {
try {
id = (Long)hibernateTemplate.save(user);
}
catch (DataAccessException e) {
e.printStackTrace();
retryCount++;
System.out.println("Retry Count = " + retryCount);
if (retryCount > 3) {
throw new AppNonFatalException(e.getLocalizedMessage(), "10000", e.getMessage(), e);
}
}
catch (Exception e) {
/* not coming inside this block too second time onwards */
System.out.println("Pure Exception");
}
}
return id;
}
}
I read that RuntimeExceptions should not be caught. Then how do I retry the operation. Should I retry at the service layer? Am I missing something? Any help is appreciated.
From https://community.oracle.com/docs/DOC-983543:
Unchecked exceptions are exceptions
that do not need to be declared in a
throws clause. They extend
RuntimeException. An unchecked
exception indicates an unexpected
problem that is probably due to a bug
in the code.
Since DataAccessException is a RuntimeException, you might want to check what is the real cause of the exception and fix it instead of catching it and retry the operation.