1

Until now, I thought that every Java exception has to be created somewhere by a constructor, as I can create on my own, custom exceptions:

throw new Exception();

But now it seems that I have to handle some exception from JavaMail - MessagingException. It comes from the method Store.close (inherited from Service class).

I went there (I need to check when this exception is thrown so I know what can be wrong) and I see that this method calls two other methods - none of them throw an exception!

public synchronized void close() throws MessagingException {
    setConnected(false);
    notifyConnectionListeners(ConnectionEvent.CLOSED);
}

As far as I understand, this is checked Exception (neither Error nor RuntimeException), so how is it possible that it doesn't have to be declared in any of used by close method commands? It is also not created here, in this method.

Devin Snyder
  • 142
  • 2
  • 10
Line
  • 1,529
  • 3
  • 18
  • 42
  • 7
    That particular implementation won't throw `MessagingException`, but subclasses overriding it could. – Jon Skeet May 16 '17 at 10:28
  • @Jon Skeet Could, but not has to... Don't you think it's a little stupid that now I have to catch/throw exception which is impossible to occur? And still, if they COULD throw these exceptions, why is this needed to be declared in this Service class? It wouldn't be better to just leave it and optionally declare in overriding methods? – Line May 16 '17 at 10:32
  • 1
    In what way is it impossible? What makes you *so* sure that you'll be using a subclass which doesn't override it in a way that means the exception *can* be thrown? So no, I don't think it's stupid at all. – Jon Skeet May 16 '17 at 10:33
  • @JonSkeet I'm only using one subclass - Store. And I have no idea how this close method should throw exception for me. Despite of this, I have to handle this phantom-exception of Store class. – Line May 16 '17 at 10:35
  • Well if you're that confident it'll never be thrown, just catch it and rethrow it wrapped in a `RuntimeException` with a message saying "This should never happen". But the idea that an abstract class can declare a method with an implementation that declares an exception that can't be thrown by *that* implementation certainly *isn't* "stupid". – Jon Skeet May 16 '17 at 10:38
  • If it *really, really* bothers you and you're creating the `Store` instance, you could create your own subclass of `Store` that overrides `close`, calling `super.close()` in a try block (and catching/rethrowing as above) and without declaring that the method can throw. You'll need the *compile-time* type to be that type though when you call close though. – Jon Skeet May 16 '17 at 10:40
  • I'm not so confident, I just don't see where this exeption can be thrown... I would like to handle it properly. Can it be thrown by one of two methods (contained in close method), when they don't declare throwing anything? – Line May 16 '17 at 10:43
  • 1
    Nope, neither of those methods should throw that exception. *This implementation* shouldn't throw that exception. The exception is declared to *allow* subclasses to throw it. Note that you can't be using `Store` directly either, as that's still a subclass. So, how sure are you about which subclass of `Store` you *are* using, and that it doesn't override `close` in a way that might involve `MessagingException` being thrown? – Jon Skeet May 16 '17 at 10:44
  • @Jon Skeet: ok. I didn't notice that I'm not using Store directly. I know which inherited class I'm using, because I'm defining it directly. But you're - that's the point. Method close() in subclass of Store throws this MessageException. I think it's too hard for me to deduce from code, what this exception means, but it doesn't matter now. Can you post this suggestion - about subclass of Store - as an answer, so I could accept it? Thanks! – Line May 16 '17 at 11:26

2 Answers2

3

The exception being declared isn't about what that implementation can throw - it's about what that implementation or the implementation in subclasses can throw. Service is an abstract class - and so are the two direct subclasses implemented by JavaMail (Transport and Store). Even if neither of those overrides close(), it's still entirely possible that the concrete implementation you use may override close() and its implementation may throw MessagingException.

Does it make sense from an API design viewpoint? I'd have to look more closely at JavaMail to be any kind of judge of that, and thankfully I haven't had to use JavaMail for a long time.

Does it makes sense from a language viewpoint? Absolutely. It's entirely reasonable to have an implementation which doesn't throw a particular checked exception, but anticipates that concrete subclasses may need to.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

The JLS about method declaration says

The requirement to declare checked exceptions allows a Java compiler to ensure that code for handling such error conditions has been included. Methods or constructors that fail to handle exceptional conditions thrown as checked exceptions in their bodies will normally cause compile-time errors if they lack proper exception types in their throws clauses. The Java programming language thus encourages a programming style where rare and otherwise truly exceptional conditions are documented in this way.

Basicly, it your are sure that the code won't compile if the exception is not handle. So even if it is not thrown in this implementation, it could be in a subclass.

Read the full page for more detailed informations.

public class Mother{
    public foo() throws Exception{
         system.out.println("I am mother");
    }
}

public class Daughter extends Mother{

    @Override
    public foo() throws Exception{
         throws new Exception("I am a teenager !!");
    }
}

Since this is permited

Mother m = new Daughter();

You loose the real type of the instance so luckily the compiler will scream if you do

m.foo(); //will not compile

Note that you can't have the methods from mother without any throws declaration if the overrided methods in a subclass need to throws something. It is forbiden, you can't add or use a super class of an exception in the subclass throws declaration

AxelH
  • 14,325
  • 2
  • 25
  • 55
  • But this method is not even overrided in subclass. And I'm not creating any subclasses, I'm just using one of them. Imagine that you have Mother class throwing exception and Son class which not throwing Exception... This is the case. I'm using Son and I have to catch in some way exception which won't occur if I understand correctly... Because Son class doesn't have foo method. And Store is abstract class, so you sure I can declare it in that way? – Line May 16 '17 at 10:38
  • @Line Not yet ... but if in the futur someone decide to override it, it would be compatible with existing source. So your `Son` that don't throw a method would work just like my `Daughter` because you would already catch the `Exception`. Now, you want to know when those could occurs, sometimes you can't, check the javadoc, if there is no description, just prepare for the worst ;) – AxelH May 16 '17 at 10:44
  • 2
    @Line If an abstract method declares it can throw a checked exception, that is part of the **contract** of that method. You are coding against the contract, not a specific implementation. Since the implementation used can be determined at runtime, you're never sure if implementation can or can't throw the exception. So you have to deal with it accordingly by either declaring to delegate upwards or catching it. – G_H May 16 '17 at 10:46
  • @Axel: I'm using this class as it is now. If someone in the future will change this class, what confidence I have that other part of the code will work properly? This thought is some madness. Why do I need description when I have actual code and it seems to deny presence of such exceptions? I don't understand this - how checked exception can be thrown by method which doesn't declare it... And it's the abstract method which declaring exception and doesn't provide a way to throw it. – Line May 16 '17 at 10:52
  • @G_H What you mean by "the implementation used can be determined at runtime"? I think that I know exactly which implementation will be used, I assume that I'm looking just now at it's code... Why not? – Line May 16 '17 at 10:54
  • @Line `throws` don't means `Exception` are thrown but that it could be thrown. Like _G_H_ said, this is a contract and since developer don't modify the methods declaration to keep the version compatible, thrust me, it will work. And if it is retrocompatible, it will do exactly the same thing. This is not madness or we could not run codes develop in Java 6 with Java 8. And your actual code could be updated to include a subclass, I could create an inner class overriding that methods if I want (if it is not final). – AxelH May 16 '17 at 10:57
  • @Line `AbstractClass abstract = someBoolean ? new Implementation1() : new Implementation2();`. So, which implementation are you using? If `someBoolean` depends on user input, how does the compiler know? – G_H May 16 '17 at 11:09
  • I am creating new code, so there is nothing to be "updated". Can you specify which subclass should I use? Store, as I'm using right now? Or maybe I should extend Store class? Even if I override this method (you see, it has no "final" keyword, so I assume it's not final). – Line May 16 '17 at 11:14
  • @G_H Now I understand, thanks. But in this case, this abstract class has two implementations, and none of them doesn't have its own {close} function. So I don't see purpose of throwing some particular kind of Exception, with though of the future or what? – Line May 16 '17 at 11:18
  • 3
    @Line It's as Jon Skeet mentions in his answer. Close methods often may require certain resource cleanup, such as explicitly closing connections, handling some underlying native interface that isn't garbage collected etc. Things may fail, so the method foresees this by declaring a `MessagingException` that's a catch-all wrapper for any underlying issue. Whether this **can** actually occur depends entirely on the implementation. Does this make it a pain to have to forcibly handle all those exceptions somewhere? Yes, it does. Checked exceptions are certainly not without controversy. – G_H May 16 '17 at 11:37