Why is Throwable.fillInStackTrace() method public? Why would someone use it?

后端 未结 6 752
不思量自难忘°
不思量自难忘° 2020-12-13 07:12

I\'m curious why is method fillInStackTrace of java.lang.Throwable public?

This method replaces original stack trace with that from the pl

相关标签:
6条回答
  • 2020-12-13 07:30

    One legitimate use case for Throwable.fillInStackTrace() is for non-local control flow:

    For example, within my TrueZIP framework, I use a complex chain of decorators for file system controllers. One of the controllers in this chain is an instance of the class FsLockController. This object is responsible for managing a ReentrantReadWriteLock for the file system. Now a file system controller somewhere deeper in this chain might detect that a write-lock is required, but only a read-lock has been acquired by the FsLockController. Because you can't upgrade a read-lock to a write-lock without dead-locking, an exception must get thrown, which happens to be an instance of the class FsNeedsWriteLockException. The decorating FsLockController will then catch this exception, release the read-lock and acquire the write-lock before retrying the operation again.

    This kind of non-local control flow works actually very well, but there is one thing to consider: Throwing and catching an exception is cheap, but filling in or examining its stack trace is expensive. Now because this particular exception type is solely thrown and catched within this file system controller chain, I do not need a stack trace at all and so I can safely override Throwable.fillInStackTrace() with an empty method body in order to suppress this expensive operation.

    Source code for the base class of this exception type can be seen here.

    0 讨论(0)
  • 2020-12-13 07:31

    A similar question provides the answer.

    According to the JLS, by default, the stacktrace is filled in when the exception is instantiated. However, there are times that you might want to "reset" the stack to some more useful location when rethrowing.

    To allow this functionality, we have fillInStackTrace()

    EDIT

    Well, today I learned the Java standard library specification was removed from the JLS after revision 1. As the preface to the second edition states:

    The specifications of the libraries are now far too large to fit into this volume, and
    they continue to evolve. Consequently, API specifications have been removed from
    this book. The library specifications can be found on the Web; this specification
    now concentrates solely on the Java programming language proper.
    

    As such, we really need to look more closely at the javadoc to figure this out. The API is here surprisingly loose. The entire relevant portions are from the header, which states:

    Instances of two subclasses, Error and Exception, are conventionally used to indicate   
    that exceptional situations have occurred. Typically, these instances are freshly 
    created in the context of the exceptional situation so as to include relevant 
    information (such as stack trace data).
    

    And java.lang.Throwable.printStackTrace() is

    Prints this throwable and its backtrace to the standard error stream.
    

    My belief is that this is to allow VM implementors to provide whatever is the most performant/appropriate implementation for their context. With this context, having the explicit fillInStackTrace() public makes even more sense.

    By default, the Virtual Machines provides you with it's best effort backtrace location. Making fillInStackTrace() public allows developers to refine further.

    --

    one final edit :)

    I managed to track down a remaining link to the relevant bits of the JLS First Edition and I'd like to offer one further reason why the method is public. It's for better or worse a common explanation in Java.

    It was always been this way.

    0 讨论(0)
  • 2020-12-13 07:34

    Perhaps you want to catch an exception and throw a new one that does not encapsulate your previous exception. getStackTrace from the caught one, and set the stackTrace for the new one.

    This would also work when you have a singleton exception, instantiated once like:

    private static Exception theException = new MyException();
    

    that is thrown multiple times. This would set the stackTrack to something related to the caught exception without the need to expensively create a new exception every time. I think this is how Scala does its continue and break constructs.

    try {
        ....
    } catch (OtherException oe) {
        theException.fillStackTrace(oe.getStackTrace());
        theException.setMessage(...); //etc
        throw theException;
    }
    

    Using static exceptions can be tricky if it can be thrown multiple times concurrently (i.e. in threads)

    0 讨论(0)
  • 2020-12-13 07:38

    Here is one reasonable case: to hide details of your application from unauthorized user. For example you do not want to expose stack trace of exception thrown when license key is expired because it will simplify hacker's work.

    0 讨论(0)
  • 2020-12-13 07:39

    One reason is for performance. Throwing and catching an exception is cheap; the expensive part is filling in the stack trace. If you override fillInStackTrace() to do nothing, creating an exception also becomes cheap.

    With cheap exceptions, you can use exceptions for flow control, which can make the code more readable in certain situations; you can use them when when implementing JVM languages where you need more advanced flow control, and they are useful if you are writing an actors library.

    0 讨论(0)
  • 2020-12-13 07:45

    One possibly legitimate use is creating an exception in a different place from where you are actually throwing. For instance, maybe you have an application where you provide a plugin facility for generating custom exceptions. Since the stacktrace is filled in on construction, the trace of the exception will include possibly misleading information (it will include calls into the custom exception factory). thus, your application would call fillInStackTrace() on the exception after generation by the custom factory to give a more accurate stack trace to the eventual receiver of the exception.

    This rejected bug indicates that you are not the only one confused by the need for this method.

    0 讨论(0)
提交回复
热议问题