4

Consider the following scenario

public class A extends Throwable {}

public class B extends A {}

public class C
{
    public void f() throws A, B
    {
        // Some condition
            throw new A();

        // Some condition 
            throw new B();
    }

    void g() 
    {
        f();
    }
}

With the above code, the compiler will warn against not catching (or not declaring as throws)

C.java:17: unreported exception A; must be caught or declared to be thrown
        f();
         ^

If I fix this with changing g to

void g() throws A

then I get no more warnings (B gets implicitly caught by catching A)

Is there a way to make the compiler report all uncaught exceptions including the base class ones (like B here).

One way is to change g() and declare it as

public void f() throws B, A

In which case, the compiler will first report B & once I add B to the throw spec of g, it will report A.

But this is painful because

  • This is a 2 step process
  • I may not have control of function f to change it's throw specs.

Is there a better way to make compiler report all exceptions?

I am not saying that the compiler is doing something wrong here - what I am asking is - "Is there a way to make the compiler report all the exceptions?". Or is a there a tool which helps me get this information automatically.

The function f throws A & B under different circumstances. If I am the author of g, I don't to accidentally suppress the information that calling g may throw B - which is what will happen if I declare g as throws A instead of declaring it as throws B, A. Is there a way to ask the compiler to detect this and warn me about it.

Again, I am not saying the compiler is doing something wrong by not warning me against this. All I am asking is if there is a way to make the compiler do what I want. Or a tool which reports this?

user93353
  • 13,733
  • 8
  • 60
  • 122
  • 3
    The compiler isn't doing any 'warning' here. It is giving you a *compilation error* according to the defined semantics of Java. Those same semantics say that your other examples are perfectly legal, so there is nothing to warn about. – user207421 Sep 19 '13 at 05:15
  • @EJP, I am not saying that the compiler is not doing the right thing. I am asking how to make the compiler do it differently. – user93353 Sep 19 '13 at 05:18
  • @user93353 In your second case, `throws B (extends A), A` is redundant; the proper response is to catch `A`, and the Java system doesn't care (and can't be made to care) whether you also catch `B` more specifically. If you're catching `IOException`, then good for you if you also have some way of usefully treating `EOFException` differently, but it's not sensical to expect the compiler to warn you about every last subclass of `IOException` that isn't getting special treatment (or is being handled with `instanceof` instead of a `catch` statement). – chrylis -cautiouslyoptimistic- Sep 19 '13 at 05:23
  • @chrylis - I know the Java system doesn't care - what I am asking is - is there a way to make it care? – user93353 Sep 19 '13 at 05:25
  • @user93353 Not without writing your own compiler or using some other form of static analysis. – chrylis -cautiouslyoptimistic- Sep 19 '13 at 05:26
  • I didn't accuse you of saying the compiler is doing the wrong thing. I said you misrepresented what the compiler is actually doing as a warning when it is an error. It's a significant mistake on your part. You aren't asking for just another warning in line with an existing warning, you are asking for a *new* warning for which there is no precedent at all, and which would be contra to the specified semantics of Java. Given that the compiler really is already doing the right thing, it isn't reasonable for you to ask for it to do something different. – user207421 Sep 19 '13 at 05:29
  • @EJP, re the quibbling about errors and warnings, I come from the `C++` world, where the C++ standard refers to refer to both Errors and Warnings as Diagnostics - the compiler implemented is free to chose whether it wants to implement a particular diagnostic as a warning or error. So sorry about that. – user93353 Sep 19 '13 at 05:35
  • @chrylis - is there any existing static analysis tool which will help me with this? – user93353 Sep 19 '13 at 05:35
  • 4
    If B is so important that it should be handled explicitly don't derive it from A. – Henry Sep 19 '13 at 05:44
  • I don't think that's an accurate representation of the requirements for C++ language implementations: it seems to me that the standard doesn't define warnings at all, and that all diagnostics referred to are errors. However the point is entirely immaterial as we are in the world of Java here. The difference between errors and warnings is not a 'quibble'. – user207421 Sep 19 '13 at 05:49
  • @Henry - I am not the author of the function `f` or of the exception hierarchy. – user93353 Sep 19 '13 at 06:02
  • @EJP, the C++ standard refers to everything as 'diagnostic messages'. And re the fact that the point is immaterial to the java world - I know, that's why I wrote `sorry about that` in my last comment. What more do you want - a formal apology? – user93353 Sep 19 '13 at 06:07
  • You've already done that and I missed it, my own apology for that. – user207421 Sep 19 '13 at 06:12
  • I don't think the Java compiler really has arguments in the way gcc has. But with the best Java IDEs you can surely create/activate some warning templates that would fix that sort of thing. What you are asking is quite advance context analysis. – Thibault D. Sep 21 '13 at 16:03

2 Answers2

3

I am not trying to sound patronizing or anything. I will probably say a lot of stuff you already know. But bear with me, while I try to explain why solving your problem will not be possible using compiler warnings.

Deriving two classes from each other, never mind if they are exception classes or not, means, they are in a is-a relation. For example:

public class Vehicle {}

public class Car extends Vehicle {}

public class Boat extends Vehicle {}

means: Car is a Vehicle. Boat is a Vehicle.

With throws, or more to the point, catch (later on), you specify the type you want to throw/be caught. Now, assuming that Vehicle was derived from Exception, you could do this:

try
{
    // ...
}
catch (Car c)
{
    // You caught a car. Not any vehicle, a real, honking car.
}

By doing this, however:

try
{
    // ...
}
catch (Vehicle v)
{
    // You caught some vehicle. Any vehicle.
}

you specify that you do not care if you catch cars, boats, bicycles or whatever, as long as it is mobile and transports passengers or cargo. Because a car is a vehicle. And a boat is a vehicle.

To sum up, what you are trying to do goes completely against the very idea of the object oriented approach. You cannot make the compiler report any "suppressed" or "hidden" exceptions, because they really are not. With throws, they are very much defined, and with catch, they are very much handled. So the compiler does not even understand your problem, let alone offer some way to prevent it.

As the comments say, a static code analysis would pretty much be the only option to do what you want to do. Something which I have used for occasions like these, is Checkstyle. Since what you want is quite unusual, I do not think that Checkstyle has a predefined check for what you want. In fact, it DOES have a check for the exact opposite.

So you will probably have to write your own check for it, but Checkstyle allows this rather easily. I would start by reading the source code of the RedundantThrows check, then doing the opposite of what it does. This should make your custom check to fail if you do not list ALL thrown checked exceptions in the method throws signature.

Jan Dörrenhaus
  • 6,581
  • 2
  • 34
  • 45
  • You are totally misunderstanding my question - I am not asking for a way to report uncaught `Car` when I am catching `Vehicle`. I am asking for a way to report uncaught `Car` when I am not catching any exception and the `throw spec` declares the exceptions in the order `throws Vehicle, Car`. – user93353 Sep 21 '13 at 18:11
  • No, I am not, actually, but apparently you misunderstood my answer. I used `catch` instead of `throws` just because it is easier to understand. The problem, and answer, are exactly the same. `throws Vehicle, Car` is redundant, as far as the compiler is concerned, because a `Car` is a `Vehicle`. So `throws Vehicle` already encompasses `Car`, `Boat`and all possible derivations of `Vehicle`. The point of my answer was the sentence I have now written in bold. – Jan Dörrenhaus Sep 21 '13 at 18:23
  • I want a way to find this information - it doesn't matter whether it comes from a compiler or any other tool. – user93353 Sep 22 '13 at 00:18
  • When I wrote my answer, you were just asking for a way to make the compiler do what you want ;) I just added something to my answer, regarding tools. – Jan Dörrenhaus Sep 22 '13 at 12:16
  • Just FYI - the Eclipse Java Compiler reports exactly what I want. – user93353 Sep 25 '13 at 05:39
1

This is a compiler specific behavior. When having your scenario inside Eclipse, the compiler will tell about both exceptions in the error list though only one is shown in the tool-tip. More interesting, when using the automated fix, either adding catch clauses or throws declarations, Eclipse will always add both (in other words: all exceptions) ignoring any subclass relationships between the exceptions. The order of the declarations has no impact on this behavior. So maybe you just want to use Eclipse :^).

Holger
  • 285,553
  • 42
  • 434
  • 765