Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

[Inheritance] Throws clause methods and constructors

 
Rob Daniel
Greenhorn
Posts: 4
2
  • Likes 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey there!

I'm new here and I'm storming in this Big Moose Saloon with a big question, so buckle up! ;)


Could someone please explain and answer the following questions regarding Class B:

Overriding the method
What are my possibilities when overriding m() exception-wise? From what I understand I can choose between:
  • Throwing nothing
  • Throwing the same exception as m() from A
  • Throwing a subclass of the exception thrown by m() from A.

  • But why throw nothing? Because I could rewrite the method so it wouldn't throw any exception at all or I could use a try-catch to avoid a throw clause, I guess?
    But then what if I want to throw lots of other exceptions too because I want to write very dangerous code. Why am I not allowed to generalize the exception to Exception instead of IOException for example?

    Constructors
    What are my possibilities when creating B() exception-wise? From what I understand I can choose between:
  • Throwing the same exception as A()
  • Throwing a superclass of the exception thrown by A().

  • But why? Again I guess it is because when super() is called there is always the possibility the IOException is thrown because of A()'s code and adding a throws clause to B() for IOException or a superclass of IOException catches it. And I understand that catching it with a try-catch is not a possibility because super() needs to be the first statement.
    But why is it allowed for a constructor to widen the exception clause to superclasses while methods can't?


    Thanks in advance!
     
    Jeanne Boyarsky
    author & internet detective
    Marshal
    Posts: 35279
    384
    Eclipse IDE Java VI Editor
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Rob,
    Welcome to CodeRanch! First, I want to say that this is a great first question. It has all the information in it plus what you know thus far and what specifically you are puzzled about.



    Rob Daniel wrote:But why throw nothing? Because I could rewrite the method so it wouldn't throw any exception at all or I could use a try-catch to avoid a throw clause, I guess?

    Correct. Maybe you are writing test code and you want to have subclass that has m() do absolutely nothing. It would be silly to have to declare an exception just because the superclass does.

    Rob Daniel wrote:But then what if I want to throw lots of other exceptions too because I want to write very dangerous code. Why am I not allowed to generalize the exception to Exception instead of IOException for example?

    Because then other code might not compile. For example suppose, I'm using class A and have code like:


    If I call method() with class A, I'm good. It might throw an IOException, but I declare that. If I call method() with the B subclass, I'm still good because it might throw an IOException. If you were allowed to have B's implementation of m() throw Exception, now class D doesn't compile. This is a problem as D could have been written by another team or company.


    Rob Daniel wrote:But why is it allowed for a constructor to widen the exception clause to superclasses while methods can't?

    Because the restriction about not widening comes from the rules for method overriding. In the case of constructors, you aren't overriding so the exceptions can vary.
     
    Rob Daniel
    Greenhorn
    Posts: 4
    2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Awesome, it's cristal clear now! Thanks!
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I just want to add 2 little remarks to Jeanne's excellent explanation:

    1/ When a method (or constructor) has a throws-clause with one expection (or several exceptions), it means there's a chance this method will throw this exception. So there is just a possibility this exception is thrown, it's not guaranteed that each invocation will result in this exception being thrown. Remembering it like this, helped me understand why it makes sense to have an overridden method which declares no throws-clause or a throws-clause with a subclass of the exception.

    Let's assume you have an interface with a create method.


    And you'll have 2 implementation classes.
  • The 1st one uses the initials of the name of the employee as a key. Using this algorithm a duplicate key can occur. If Robert De Niro already works for the company, and I also start working as an employee for the company, the [tt]create[/tt method will throw a DuplicateKeyException (if implemented correctly because both employees have "rdn" as initials). So this implementation must have a throws-clause with DuplicateKeyException.
  • The 2nd one uses an auto-increment value as a key. Using this algorithm a duplicate key will never occur. Each employee will have a unique number. So this implementation can omit the throws-clause.


  • Both implementation classes in code (just the method declarations):


    Now what happens if you use these implementation classes using different reference variable types. If you invoke the create method on each of these reference variables, will you need to handle-or-declare the DuplicateKeyException or not (in order to compile the code without errors)?


    2/ This remark is much shorter than the 1st one I just want to nitpick a little about one of your sentences of the original post. Maybe it was even just a typo...
    Rob Daniel wrote:Again I guess it is because when super() is called there is always the possibility the IOException is thrown because of A()'s code and adding a throws clause to B() for IOException or a superclass of IOException catches it.

    First of all, your guess is spot on! That's exactly the reason why IOException (or a superclass) is allowed and a subclass isn't. Secondly, if you add a throws clause to a constructor (or method) you declare that this exception can be thrown from this constructor (or method). A throws-clause will never catch an exception. If you want to catch an exception, you'll need a try-catch block.

    Hope it helps!
     
    Guillermo Ishi
    Ranch Hand
    Posts: 789
    C++ Linux Python
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    The way I remember this for tests is B can throw the same as A or a subset of A, including nothing, which is considered a subset. Easy to remember. And then constructors are exactly bassackwards from that. Easy to remember too. This is only checked exceptions. Checked meaning those that are checked for by the compiler.
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Guillermo Ishi wrote:And then constructors are exactly bassackwards from that. Easy to remember too.

    If you know the meaning of bassackwards, which I didn't know until 5 minutes ago
     
    Rob Daniel
    Greenhorn
    Posts: 4
    2
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Roel De Nijs wrote:


    So from my understanding the compiler will judge my code by reviewing the type of my reference variable.
    So because the method create in the interface EmployeeDao and the class InitialsEmployeeDao throws a DuplicateKeyException, the compiler kindly remarks that it wants a try-catch surrounding the method call or adding the exception to the throws-clause. This will happen for line 1, 2 and 3.

    Line 4's reference type is IdEmployeeDao and his create method doesn't throw anything so the compiler doesn't give a flying moose about exception handling because there is no way a checked-exception will be thrown. And as an addition to this: if the create method of IdEmployeeDao would be updated and now throw an IdDuplicateKeyException (Just pretend it exists) which would be a subclass of DuplicateKeyException, the compiler says "Fine as long as you catch that exception or add it to the throws-clause". The compiler would only complain if I would be so badass to let my create method throw a superclass of DuplicateKeyException, because the compiler can't guarantee safe code when IdEmployeeDao's create method would be called with the reference type of EmployeeDao. Would be an ugly fight, wouldn't it?
     
    Roel De Nijs
    Sheriff
    Posts: 10662
    144
    AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Rob Daniel wrote:So from my understanding

    Your understanding is spot-on!

    Rob Daniel wrote:The compiler would only complain if I would be so badass to let my create method throw a superclass of DuplicateKeyException

    If you want to nitpick (and that's my favourite waste of time ), this is not 100% correct. The compiler will also complain if the create method throws any checked exception which is not related with DuplicateKeyException
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic