Why is exception.printStackTrace() considered bad practice?
Throwable.printStackTrace()
writes the stack trace to System.err
PrintStream. The System.err
stream and the underlying standard "error" output stream of the JVM process can be redirected by
- invoking
System.setErr()
which changes the destination pointed to bySystem.err
. - or by redirecting the process' error output stream. The error output stream may be redirected to a file/device
- whose contents may be ignored by personnel,
- the file/device may not be capable of log rotation, inferring that a process restart is required to close the open file/device handle, before archiving the existing contents of the file/device.
- or the file/device actually discards all data written to it, as is the case of
/dev/null
.
Inferring from the above, invoking Throwable.printStackTrace()
constitutes valid (not good/great) exception handling behavior, only
- if you do not have
System.err
being reassigned throughout the duration of the application's lifetime, - and if you do not require log rotation while the application is running,
- and if accepted/designed logging practice of the application is to write to
System.err
(and the JVM's standard error output stream).
In most cases, the above conditions are not satisfied. One may not be aware of other code running in the JVM, and one cannot predict the size of the log file or the runtime duration of the process, and a well designed logging practice would revolve around writing "machine-parseable" log files (a preferable but optional feature in a logger) in a known destination, to aid in support.
Finally, one ought to remember that the output of Throwable.printStackTrace()
would definitely get interleaved with other content written to System.err
(and possibly even System.out
if both are redirected to the same file/device). This is an annoyance (for single-threaded apps) that one must deal with, for the data around exceptions is not easily parseable in such an event. Worse, it is highly likely that a multi-threaded application will produce very confusing logs as Throwable.printStackTrace()
is not thread-safe.
There is no synchronization mechanism to synchronize the writing of the stack trace to System.err
when multiple threads invoke Throwable.printStackTrace()
at the same time. Resolving this actually requires your code to synchronize on the monitor associated with System.err
(and also System.out
, if the destination file/device is the same), and that is rather heavy price to pay for log file sanity. To take an example, the ConsoleHandler
and StreamHandler
classes are responsible for appending log records to console, in the logging facility provided by java.util.logging
; the actual operation of publishing log records is synchronized - every thread that attempts to publish a log record must also acquire the lock on the monitor associated with the StreamHandler
instance. If you wish to have the same guarantee of having non-interleaved log records using System.out
/System.err
, you must ensure the same - the messages are published to these streams in a serializable manner.
Considering all of the above, and the very restricted scenarios in which Throwable.printStackTrace()
is actually useful, it often turns out that invoking it is a bad practice.
Extending the argument in the one of the previous paragraphs, it is also a poor choice to use Throwable.printStackTrace
in conjunction with a logger that writes to the console. This is in part, due to the reason that the logger would synchronize on a different monitor, while your application would (possibly, if you don't want interleaved log records) synchronize on a different monitor. The argument also holds good when you use two different loggers that write to the same destination, in your application.
why it is not recommended to use e.printstacktrace() by sonar?
Error handling can be tricky in any environment, java included. I haven't used sonar, but I can comment on general good practices for java error handling.
e.printStackTrace() is generally discouraged because it just prints out the stack trace to standard error. Because of this you can't really control where this output goes.
The better thing to do is to use a logging framework (logback, slf4j, java.util.logging, log4j, etc) because then you can control where the errors are logged to and what the log retention policy is.
And generally you'll want to catch the exception and if it's unexpected behavior, log it and either throw a new exception (probably specific to your application) or do whatever you have to do to continue operating gracefully.
If you're using java.util.logging, you can do something like the following:
class YourClass
{
Logger logger = Logger.getLogger(YourClass.class.getName());
...
public void someMethod() throws YourException
{
try
{
// your code here
} catch (NullPointerException e)
{
String message = "Unexpected NullPointerException in processing!";
logger.log(Level.ERROR, message, e);
throw new YourException(message, e);
}
}
}
Hope this helps!
printStackTrace vs Logger Frameworks in Java
To 2)
The logging frameworks aren't better file handler but, for example, extract the configuration of the logging out of the code. So when you change the configuration (e.g. other detail level of logs for development and production) you don't have to change the code - you just use other logging framework configurations for each test stage.
If you want to change the log file names, the log file size (rotation) or the specific log detail of different packages or classes, you can easily do that by modifying the configuration.
printStackTrace() in a finished product. When and why?
You need to shift your thought process a bit when dealing with error 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 work around, if you ask me.
In production and pre-prod systems and even in distributable spftware where you distribute a desktop application to users for running on PCs you may or may not have dedicated access to console. Further more what prints on console is lost once the console is closed or 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 scenarios 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 wont suffice. Thus incidentally the catch block should have a log statement to log the exception.
What is the use of printStackTrace() method in Java?
It's a method on Exception
instances that prints the stack trace of the instance to System.err
.
It's a very simple, but very useful tool for diagnosing an exceptions. It tells you what happened and where in the code this happened.
Here's an example of how it might be used in practice:
try {
// ...
} catch (SomeException e) {
e.printStackTrace();
}
Note that in "serious production code" you usually don't want to do this, for various reasons (such as System.out
being less useful and not thread safe). In those cases you usually use some log framework that provides the same (or very similar) output using a command like log.error("Error during frobnication", e);
.
Printing the stack trace vs the exception itself
The difference between them is that print e returns the type of exception and error message while printStackTrace returns the whole stacktrace of the exception. printStackTrace is more beneficial to be used while debugging.
Example:
print e:
java.lang.IndexOutOfBoundsException
e.printStackTrace():
java.lang.IndexOutOfBoundsException: Index: 8, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.get(ArrayList.java:322)
at com.o2.business.util.Trial.test(CommonUtilsTest.java:866)
printStackTrace might be good for programmer, but it is not readable and user-friendly for end users. As far as I know, printStackTrace prints the results in the default Errorstream: your console. For better practices, you can check the link: http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html
what's wrong with e.printStackTrace() for an unknown exception
Because it doesn't use the logger system, it goes directly to the stderr
which has to be avoided.
edit: why writing directly to stderr has to be avoided ?
In answer to your question, @shinynewbike, I have slightly modifed my answer. What it has to be avoided is to write directly to stderr
without using a logger
capability.
loggers
provide useful features to change logging traces by priority and packages, among other things they also allow to redirect traces to different output mechanisms ... queues, files, databases, streams ...
When you write directly to System.err
or System.out
then you lose these features, and what is worse if you mix logger
and System.err.write
you might end up getting traces in different 'files' which will make debugging your system difficult.
Avoid printStackTrace(); use a logger call instead
It means you should use logging framework like logback or log4j and instead of printing exceptions directly:
e.printStackTrace();
you should log them using this frameworks' API:
log.error("Ops!", e);
Logging frameworks give you a lot of flexibility, e.g. you can choose whether you want to log to console or file - or maybe skip some messages if you find them no longer relevant in some environment.
Related Topics
Getting Strange Output When Printing Result of a String Comparison
"Loadstylesheetunprivileged" Error When Trying to Use CSS Stylesheet with Javafx
Understand Arraylist Indexoutofboundsexception in Android
Error Launching Android Studio: Failed to Create Jvm: Error Code-6
Source Code Does Not Match the Bytecode' When Debugging on a Device
Android: How to Parse Url String with Spaces to Uri Object
Android Audiorecord Class - Process Live Mic Audio Quickly, Set Up Callback Function
How to Navigate from One Screen to Another Screen
How to Resume an Interrupted Download - Part 2
How to Implement in Java ( Jtextfield Class ) to Allow Entering Only Digits
Input and Output Binary Streams Using Jersey
Javafx - How to Create a Thin Menubar
Customised Listview Using Arrayadapter Class in Android
Change Listview Background - Strange Behaviour