When to choose checked and unchecked exceptions

前端 未结 18 2300
南方客
南方客 2020-11-22 04:13

In Java (or any other language with checked exceptions), when creating your own exception class, how do you decide whether it should be checked or unchecked?

My inst

相关标签:
18条回答
  • 2020-11-22 04:56

    Here is my 'final rule of thumb'.
    I use:

    • unchecked exception within the code of my method for a failure due to the caller (that involves an explicit and complete documentation)
    • checked exception for a failure due to the callee that I need to make explicit to anyone wanting to use my code

    Compare to the previous answer, this is a clear rationale (upon which one can agree or disagree) for the use of one or the other (or both) kind of exceptions.


    For both of those exceptions, I will create my own unchecked and checked Exception for my application (a good practice, as mentionned here), except for very common unchecked exception (like NullPointerException)

    So for instance, the goal of this particular function below is to make (or get if already exist) an object,
    meaning:

    • the container of the object to make/get MUST exist (responsibility of the CALLER
      => unchecked exception, AND clear javadoc comment for this called function)
    • the other parameters can not be null
      (choice of the coder to put that on the CALLER: the coder will not check for null parameter but the coder DOES DOCUMENT IT)
    • the result CAN NOT BE NULL
      (responsibility and choice of the code of the callee, choice which will be of great interest for the caller
      => checked exception because every callers MUST take a decision if the object can not be created/found, and that decision must be enforced at the compilation time: they can not use this function without having to deal with this possibility, meaning with this checked exception).

    Example:


    /**
     * Build a folder. <br />
     * Folder located under a Parent Folder (either RootFolder or an existing Folder)
     * @param aFolderName name of folder
     * @param aPVob project vob containing folder (MUST NOT BE NULL)
     * @param aParent parent folder containing folder 
     *        (MUST NOT BE NULL, MUST BE IN THE SAME PVOB than aPvob)
     * @param aComment comment for folder (MUST NOT BE NULL)
     * @return a new folder or an existing one
     * @throws CCException if any problems occurs during folder creation
     * @throws AssertionFailedException if aParent is not in the same PVob
     * @throws NullPointerException if aPVob or aParent or aComment is null
     */
    static public Folder makeOrGetFolder(final String aFoldername, final Folder aParent,
        final IPVob aPVob, final Comment aComment) throws CCException {
        Folder aFolderRes = null;
        if (aPVob.equals(aParent.getPVob() == false) { 
           // UNCHECKED EXCEPTION because the caller failed to live up
           // to the documented entry criteria for this function
           Assert.isLegal(false, "parent Folder must be in the same PVob than " + aPVob); }
    
        final String ctcmd = "mkfolder " + aComment.getCommentOption() + 
            " -in " + getPNameFromRepoObject(aParent) + " " + aPVob.getFullName(aFolderName);
    
        final Status st = getCleartool().executeCmd(ctcmd);
    
        if (st.status || StringUtils.strictContains(st.message,"already exists.")) {
            aFolderRes = Folder.getFolder(aFolderName, aPVob);
        }
        else {
            // CHECKED EXCEPTION because the callee failed to respect his contract
            throw new CCException.Error("Unable to make/get folder '" + aFolderName + "'");
        }
        return aFolderRes;
    }
    
    0 讨论(0)
  • 2020-11-22 05:00

    It's not just a matter of the ability to recover from the exception. What matter most, in my opinion, is whether the caller is interested in catching the exception or not.

    If you write a library to be used elsewhere, or a lower-level layer in your application, ask yourself if the caller is interested in catching (knowing about) your exception. If he is not, then use an unchecked exception, so you don't burden him unnecessarily.

    This is the philosophy used by many frameworks. Spring and hibernate, in particularly, come to mind - they convert known checked exception to unchecked exception precisely because checked exceptions are overused in Java. One example that I can think of is the JSONException from json.org, which is a checked exception and is mostly annoying - it should be unchecked, but the developer simply haven't thought it through.

    By the way, most of the time the caller's interest in the exception is directly correlated to the ability to recover from the exception, but that is not always the case.

    0 讨论(0)
  • 2020-11-22 05:03

    You're correct.

    Unchecked exceptions are used to let the system fail fast which is a good thing. You should clearly state what is your method expecting in order to work properly. This way you can validate the input only once.

    For instance:

    /**
     * @params operation - The operation to execute.
     * @throws IllegalArgumentException if the operation is "exit"
     */
     public final void execute( String operation ) {
         if( "exit".equals(operation)){
              throw new IllegalArgumentException("I told you not to...");
         }
         this.operation = operation; 
         .....  
     }
     private void secretCode(){
          // we perform the operation.
          // at this point the opreation was validated already.
          // so we don't worry that operation is "exit"
          .....  
     }
    

    Just to put an example. The point is, if the system fails fast, then you'll know where and why it did fail. You'll get an stacktrace like:

     IllegalArgumentException: I told you not to use "exit" 
     at some.package.AClass.execute(Aclass.java:5)
     at otherPackage.Otherlass.delegateTheWork(OtherClass.java:4569)
     ar ......
    

    And you'll know what happened. The OtherClass in the "delegateTheWork" method ( at line 4569 ) called your class with the "exit" value, even when it shouldn't etc.

    Otherwise you would have to sprinkle validations all over your code and that's error prone. Plus, sometimes it is hard to track what went wrong and you may expect hours of frustrating debugging

    Same thing happens with NullPointerExceptions. If you have a 700 lines class with some 15 methods, that uses 30 attributes and none of them can be null, instead of validating in each of those methods for nullability you could make all those attributes read-only and validate them in the constructor or factory method.

     public static MyClass createInstane( Object data1, Object data2 /* etc */ ){ 
          if( data1 == null ){ throw NullPointerException( "data1 cannot be null"); }
    
      }
    
    
      // the rest of the methods don't validate data1 anymore.
      public void method1(){ // don't worry, nothing is null 
          ....
      }
      public void method2(){ // don't worry, nothing is null 
          ....
      }
      public void method3(){ // don't worry, nothing is null 
          ....
      }
    

    Checked exceptions Are useful when the programmer ( you or your co-workers ) did everything right, validated the input, ran tests, and all the code is perfect, but the code connects to a third party webservice that may be down ( or a file you were using was deleted by another external process etc ) . The webservice may even be validate before the connection is attempted, but during the data transfer something went wrong.

    In that scenario there is nothing that you or your co-workers can do to help it. But still you have to do something and not let the application just die and disappear in the eyes of the user. You use a checked exception for that and handle the exception, what can you do when that happens?, most of the time , just to attempt to log the error, probably save your work ( the app work ) and present a message to the user. ( The site blabla is down, please retry later etc. )

    If the checked exception are overused ( by adding the "throw Exception" in the all the methods signatures ) , then your code will become very fragile, because everyone will ignore that exception ( because is too general ) and the quality of code will be seriously compromised.

    If you overuse unchecked exception something similar will happen. The users of that code don't know if something may go wrong an a lot of try{...}catch( Throwable t ) will appear.

    0 讨论(0)
  • 2020-11-22 05:03

    I agree with the preference for unchecked exceptions as a rule, especially when designing an API. The caller can always choose to catch a documented, unchecked exception. You're just not needlessly forcing the caller to.

    I find checked exceptions useful at the lower-level, as implementation detail. It often seems like a better flow of control mechanism than having to manage a specified error "return code". It can sometimes help see the impact of an idea for a low level code change too... declare a checked exception downstream and see who would need to adjust. This last point doesn't apply if there are a lot of generic: catch(Exception e) or throws Exception which is usually not too well-thought out anyway.

    0 讨论(0)
  • 2020-11-22 05:04

    Checked exceptions are useful for recoverable cases where you want to provide information to the caller (i.e. insufficient permissions, file not found, etc).

    Unchecked exceptions are used rarely, if at all, for informing the user or programmer of serious errors or unexpected conditions during run-time. Don't throw them if you're writing code or libraries that will be used by others, as they may not be expecting your software to throw unchecked exceptions since the compiler doesn't force them to be caught or declared.

    0 讨论(0)
  • 2020-11-22 05:06

    The rule I use is: never use unchecked exceptions! (or when you don't see any way around it)

    From the point of view of the developer using your library or the end-user using your library/application it really sucks to be confronted with an application that crashes due to an uncought exception. And counting on a catch-all is no good either.

    This way the end user can still be presented with an error message, instead of the application completely disappearing.

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