Search code examples
javaerror-handlingruntime-errorclassloaderrunnable

printStackTrace() in a finished product. When and why?


I've come to the conclusion after reading from many sources that using printStackTrace for error handling is bad practice. Here's one.

Now I'm struck curious: in what cases is printing the stacktrace a valid solution? For the sake of the argument, let's assume we aren't working on a system such as a microwave or a banana, but a basic out-of-the-shelf PC.

The reason I'm asking this could be seen as a question in itself, but I'll tell you about it anyhoo:

I'm developing a snake-like game that can be played with AIs, and is intended for that purpose. All such AIs should extend an abstract class called SnakeLogic. All such AIs should also reside in their standalone .jar archives in a specific folder, from where the main program can find them and list them using classloaders.

The user can then choose one of his/her AIs from a list, should all stars fall in line, and play a game with this AI.

Now, I have a method in my main program that gets the next move from the AI like so:

public void startGame(int speed) {        
    gameInterface.showWindow();
    Runnable moveCmd = () -> {
        try {

            for (Player player : snakeGame.getPlayers()) {
                if (player.isDead()) {
                    continue;
                }

                String move = player.getLogicHandler().getMove();

                Direction direction = Direction.directionFromString(move);
                snakeGame.makeMove(player, direction);
            }

            gameInterface.getFrame().repaint();
            snakeGame.wait(speed);

            if (snakeGame.gameOver()) {
                stopGame();
            }

        } catch (Exception ex) {
            ex.printStackTrace();
            stopGame();
        }
    };

    /* moveSchedule is an instance of ScheduledExecutorService */
    moveSchedule.scheduleAtFixedRate(moveCmd, 1000, speed, TimeUnit.MILLISECONDS);        
}

I'm not going to get too involved with the code above. I'd like to draw your attention to the try-catch statement, however. As you can see I print the stacktrace and end the game, should an exception occur somewhere during the execution of the moveCmd runnable. This is the source of my curiosity: If I don't print the stacktrace like this, or if I remove the try-catch entirely, I never get any errors in the case of a runtime exception during the execution of that block. Why? Is it because it's wrapped inside the runnable? Note also that the line snakeGame.makeMove(player, direction); doesn't call any code in the main program; snakeGame is an instance of a SnakeLogic, which resides in an external .jar.

Why don't I get any errors if I remove the try-catch? Also, in this case, is printing the stacktrace a good idea?

I understand this imposes two questions for you: the topic and the above. I want to emphasize the topic, so don't get too sidetracked with the second question; though insight is duly noted, there's nothing broken in my code.


Solution

  • You need to shift your thought process a bit when dealing with errors and exceptions. It is always a good practice to print the error trace. Now the question is where to print. By default, printStackTrace prints to your standard console. Of course, you can redirect that output to a log file like Tomcat does but that is a workaround, if you ask me.

    In production and pre-prod systems and even in distributable software where you distribute a desktop application to users for running on PCs, you may or may not have dedicated access to console. Furthermore, what prints on console is lost once the console is closed or the app finishes. You need to persist the errors somewhere for analysis later. Normally, folks design the app to zip and send error logs periodically to developers for analysis.

    Now if you think about the whole scenario, the bottom line is to preserve the errors somewhere for analysis later. So usually do it in a rotating log file or in DB. Console won't suffice. Thus, incidentally, the catch block should have a log statement to log the exception.