Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
149 views
in Technique[技术] by (71.8m points)

java - Why is it legal to re-throw a Throwable in certain cases, without declaring it?

I would expect the following code to raise a compile-time error on throw t;, because main is not declared to throw Throwable, but it compiles successfully (in Java 1.7.0_45), and produces the output you would expect it to if that compile-time error was fixed.

public class Test {
    public static void main(String[] args) {
        try {
            throw new NullPointerException();

        } catch(Throwable t) {
            System.out.println("Caught "+t);
            throw t;
        }
    }
}

It also compiles if Throwable is changed to Exception.

This does not compile, as expected:

public class Test {
    public static void main(String[] args) {
        try {
            throw new NullPointerException();

        } catch(Throwable t) {
            Throwable t2 = t;
            System.out.println("Caught "+t2);
            throw t2;
        }
    }
}

This compiles:

public class Test {
    public static void main(String[] args) {
        try {
            throwsRuntimeException();

        } catch(Throwable t) {
            System.out.println("Caught "+t);
            throw t;
        }
    }

    public static void throwsRuntimeException() {
        throw new NullPointerException();
    }
}

This does not:

public class Test {
    public static void main(String[] args) {
        try {
            throwsCheckedException();

        } catch(Throwable t) {
            System.out.println("Caught "+t);
            throw t;
        }
    }

    public static void throwsCheckedException() {
        throw new java.io.IOException();
    }
}

This compiles as well:

public class Test {
    public static void main(String[] args) throws java.io.IOException {
        try {
            throwsIOException();

        } catch(Throwable t) {
            System.out.println("Caught "+t);
            throw t;
        }
    }

    public static void throwsIOException() throws java.io.IOException {
        throw new java.io.IOException();
    }
}

A more complex example - the checked exception is caught by an outer catch block, instead of being declared to be thrown. This compiles:

public class Test {
    public static void main(String[] args) {
        try {
            try {
                throwsIOException();

            } catch(Throwable t) {
                System.out.println("Caught "+t);
                throw t;
            }
        } catch(java.io.IOException e) {
            System.out.println("Caught IOException (outer block)");
        }
    }

    public static void throwsIOException() throws java.io.IOException {
        throw new java.io.IOException();
    }
}

So there seems to be a special case to allow rethrowing exceptions when the compiler can determine that the caught exception is always legal to re-throw. Is this correct? Where is this specified in the JLS? Are there any other obscure corner-cases like this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is covered by JLS 11.2.2 (emphasis mine):

A throw statement whose thrown expression is a final or effectively final exception parameter of a catch clause C can throw an exception class E iff:

  • E is an exception class that the try block of the try statement which declares C can throw; and

  • E is assignment compatible with any of C's catchable exception classes; and

(...)

In other words, E, the type referenced in the doc, is the type that can be thrown, not the type of the catch clause parameter that catches it (the catchable exception class). It just has to be assignment compatible to the catch clause parameter, but the parameter's type is not used in analysis.

This is why the go out of their way to say a final or effectively final exception parameter--if t in your example were reassigned, the analysis would go out the window.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...