I'm trying to understand the difference why a child class cannot override a method implementation in the parent class to catch an Exception but no problem while catching a Error,
For example in the below scenario, when I remove "Exception" from the throws clause, it compiles fine.
class Supertest {
public void amethod(int i, String s) {
}
}
public class test extends Supertest {
public void amethod(int i, String s) throws Error, Exception {
}
}
Error is an unchecked exception. Exception is a checked exception. It's as simple as that. So it should be reasonable to have code like this:
Supertest x = new test();
x.amethod(10, "foo");
... but test.amethod() tries to impose a checked exception on the caller, so that the caller either has to catch it or propagate it. As the method it's overriding doesn't declare that exception, the overriding method can't either.
As noted in comments, fundamentally you can't override one method with a "more restrictive" one - any call to the original method must still be valid to the override.
From section 8.4.8.3 of the JLS:
More precisely, suppose that B is a class or interface, and A is a superclass or superinterface of B, and a method declaration n in B overrides or hides a method declaration m in A. Then:
If n has a throws clause that mentions any checked exception types, then m must have a throws clause, or a compile-time error occurs.
For every checked exception type listed in the throws clause of n, that same exception class or one of its supertypes must occur in the erasure (§4.6) of the throws clause of m; otherwise, a compile-time error occurs.
Throw clauses must be covariant.
This is similar to the requirement of return types of overriding methods:
SuperClass
Pet method()
SubClass
Cat method()
here Cat is a subtype of Pet, therefore the overriding is legal.
The same principle applies to throws clause, which is also part of the output of the method.
SuperClass
Pet method() throws PetException
SubClass
Cat method() throws CatException
this is legal if CatException is a subtype of PetException.
If the throw clause of a method is empty, it is implicitly RuntimeException|Error. All overriding methods must only throw subtypes of that. Excepiton|RuntimeException|Error is not a subtype of RuntimeException|Error.
Say you have
SuperTest superTest = new test();
superTest.amethod();
at compile time, methods are resolved with the declared or static type of the variable. The SuperTest#amethod is declared without throwing the checked exception Exception so its children need to follow those rules.
Error is an unchecked exception. It doesn't need to be caught. As such the parent method declaration doesn't restrict it.
If super class method doesn't declare any exception then subclass overridden method cannot declare any checked exception.
Here is Exception is checked and Error is unchecked.So you can't throw Exception.
Reference http://www.javatpoint.com/exception-handling-with-method-overriding
Related
Can anyone please explain the output of the following code, and what's the Java principle involved here?
class Mammal {
void eat(Mammal m) {
System.out.println("Mammal eats food");
}
}
class Cattle extends Mammal{
void eat(Cattle c){
System.out.println("Cattle eats hay");
}
}
class Horse extends Cattle {
void eat(Horse h) {
System.out.println("Horse eats hay");
}
}
public class Test {
public static void main(String[] args) {
Mammal h = new Horse();
Cattle c = new Horse();
c.eat(h);
}
}
It produces the following output:
Mammal eats food
I want to know how we are coming at the above result.
Overloading vs Overriding
That's not a valid method overriding, because all the method signatures (method name + parameters) are different:
void eat(Mammal m)
void eat(Cattle c)
void eat(Horse h)
That is called method overloading (see) and class Horse will have 3 distinct methods, not one. I.e. its own overloaded version of eat() and 2 inherited versions.
The compiler will map the method call c.eat(h) to the most specific method, which is eat(Mammal m), because the variable h is of type Mammal.
In order to invoke the method with a signature eat(Horse h) you need to coerce h into the type Horse. Note, that such conversion would be considered a so-called narrowing conversion, and it will never happen automatically because there's no guarantee that such type cast will succeed, so the compiler will not do it for you.
Comment out the method void eat(Mammal m) and you will see the compilation error - compilers don't perform narrowing conversions, it can only help you with widening conversions because they are guaranteed to succeed and therefore safe.
That what would happen if you'll make type casting manually:
Coercing h into the type Horse:
c.eat((Horse) h);
Output:
Cattle eats hay // because `c` is of type `Cattle` method `eat(Cattle c)` gets invoked
Because variable c is of type Cattle it's only aware of the method eat(Cattle c) and not eat(Horse h). And behind the scenes, the compiler will widen the h to the type Cattle.
Coercing both c and h into the type Horse:
((Horse) c).eat((Horse) h);
Output:
Horse eats hay // now `eat(Horse h)` is the most specific method
Rules of Overriding
The rules of method overriding conform to the Liskov substitution principle.
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
The child class should declare its behavior in such a way so that it can be used everywhere where its parent is expected:
Method signatures must match exactly. I.e. method names should be the same as well as the types of parameters. And parameters need to be declared in the same order. It is important to note that if method signatures differ (for instance like in the code snippet provided in the question, name of one of the methods was misspelled) the compiler will have no clue that these methods are connected anyhow. I.e. it no longer be considered a case of overriding, methods will be considered to be distinct, and all other requirements listed below will not be applicable. That's why it's highly advisable to add the #Override annotation to the overridden method. With it, the compiler will give a clear feedback when it fails to find a matching method in the parent classes and interfaces, if you've misspelled the name, or declared parameters in the wrong order. Your IDE will add this annotation for you if you ask it to generate a template (shortcut in IntelliJ CTRL + O).
The access modifier of an overridden method can be the same or wider, but it can not be more strict. I.e. protected method in the parent class can be overridden as public or can remain protected, we can not make it private.
Return type of an overridden method should be precisely the same in case primitive type. But if a parent method declares to return a reference type, its subtype can be returned. I.e. if parent returns Number an overridden method can provide Integer as a return type.
If parent method declares to throw any checked exceptions then the overridden method is allowed to declare the same exceptions or their subtypes, or can be implemented as safe (i.e. not throwing exceptions at all). It's not allowed to make the overridden method less safe than the method declared by the parent, i.e. to throw checked exceptions not declared by the parent method. Note, that there are no restrictions regarding runtime exceptions (unchecked), overridden methods are free to declare them even if they are not specified by the parent method.
This would be a valid example of method overriding:
static class Mammal{
void eat(Mammal m){
System.out.println("Mammal eats food");
}
}
public class Cattle extends Mammal{
#Override
void eat(Mammal c) {
System.out.println("Cattle eats hay");
}
}
public class Horse extends Cattle{
#Override
public void eat(Mammal h) throws RuntimeException {
System.out.println("Horse eats hay");
}
}
main()
public static void main(String[] args) {
Mammal h = new Horse();
Cattle c = new Horse();
c.eat(h);
}
Output:
Horse eats hay
In your example, method overloading occurs(same method name but different parameter type passed).
When you're calling c.eat(h), the compiler will know that you want to use the void eat(Mammal m) method since your h reference has the type Mammal.
If you would change the object reference to Horse or Cattle like so:
Horse h = new Horse();
The output will be:
Cattle eats hay
This happens because the compiler will use the most specific method, in this case void eat(Cattle c), based on the object reference type Horse.
You may also be interested in method overriding which uses runtime polymorphism.
Consider the following article in JLS §18.1.3 - Bounds
Here when we try to identify the set of bounds on the inference variables - we have one of the following situations:
...
throws α: The inference variable α appears in a throws clause.
...
A bound of the form throws α is purely informational: it directs resolution to
optimize the instantiation of α so that, if possible, it is not a checked exception type.
I think this statement is incorrect:
this is because ideally the throws clause is mentioned to take care of checked exceptions which can happen during the course of execution of the code.
Then why still the JLS preventing α to be a Checked Exception?
Ideally the inference variable α must be bounded to be an exception of Checked type rather than being an Unchecked variant.
Is my understanding correct here or am I missing something?
I think your interpretation/understanding of this statement is slightly misguided:
A bound of the form throws α is purely informational: it directs resolution to optimize the instantiation of α so that, if possible, it is not a checked exception type.
That line is referring to the resolution, which, as I understand it, is not about where throws α is, but about where α is inferred, conceivably the invocation of the method.
Consider this class:
static class MyClass {
public static void main(String[] args) {
MyClass.<RuntimeException>something(0); // same as MyClass.something(1);
try {
MyClass.<IOException>something(2);
} catch (IOException ex) {
// checked exception
}
}
/**
* Will throw IOException if argument is 2, a RuntimeException otherwise
*/
static <T extends Exception> void something(int a) throws T {
if (a == 2) {
throw (T) new IOException(); //of course it's a bad cast
} else {
throw (T) new Exception();
}
}
}
After analyzing the two something method, focus on the invocation in the main method:
The call MyClass.<IOException>something(0) expects an IOException. The caller knows it (assume fully documented contract rather than tightly coupled code), and handles the exception.
This already tells you that the variable can be a checked exception, contrary to what you think.
On the contrary, the call MyClass.<RuntimeException>something(0) expects a runtime exception on similar grounds.
How α (T in the above example) is inferred allows the compiler to skip forcing the caller to catch/handle the exception (if it's to look at the bound, which it'd otherwise have to)
Now about the "optimization": The type variable being bounded as extends Exception can reasonably be expected to resolve to a checked exception. But, if the caller knows that it shall be a runtime exception, it can "inform" the compiler that it's going to be a runtime exception. This is what I did by specifying RuntimeException in the type witness (RuntimeException is also the resolved type when no type argument is given explicitly).
We can spend days to interpret "optimization", but at least I as a caller did not have to try/catch the invocation, and I still didn't upset the compiler (first invocation).
Consider this example:
public class Main {
public static void main(String[] args) {
foo(() -> System.out.println("Foo"));
}
public static <T extends Exception> void foo(ThrowingRunnable<T> runnable) throws T {
runnable.run();
}
}
interface ThrowingRunnable<T extends Exception> {
void run() throws T;
}
During the inference of the type parameter T when calling foo, there will be a "throws" bound on the type variable T, and T is inferred to be RuntimeException. If not for this bound, T would have been inferred as Exception because of the T extends Exception bound. This would have meant that I needed to do:
try {
foo(() -> System.out.println("Foo"));
catch (Exception e) {
// This won't be reached!
}
I had to handle the exception, even though all I'm doing in the lambda is printing things! That doesn't seem very nice, does it?
The purpose of this bound is so that if there's no reason for the method to throw a checked exception, it doesn't throw a checked exception, so that you don't have to write so many try...catches all over the place. foo would only throw a checked exception if you do things like:
foo(() -> new FileOutputStream("foo"));
If the effect of the bound were instead to force T to be a checked exception, it wouldn't be very useful at all.
I know the method signature is including method name and its parameter list.
But how about throws Exception?
public List<ServiceStatusVo> listServiceStatuses() throws RetrieverException {
...
return list;
}
If it's not included then why I cannot pass in the following lambda:
() -> listServiceStatuses()
but I can pass in
() -> {
try {
return listServiceStatuses();
} catch (RetrieverException e) {
}
}
And also I can throw it out again
() -> {
try {
return listServiceStatuses();
} catch (RetrieverException e) {
throw e;
}
}
I know the Supplier<T> functional interface, that's what really confusing me if throws is not part of the method signature.
Thanks for the help.
It's not about the method signature directly. From JLS Sec 11.2.3:
It is a compile-time error if a lambda body can throw some exception class E when E is a checked exception class and E is not a subclass of some class declared in the throws clause of the function type targeted by the lambda expression.
This is a little surprising - I must admit that my initial thought was that the exception is part of the method signature.
But remember that "checked exception" means compile-time checked exception: the compiler makes sure that you have handled all checked exceptions; but once it has been compiled, checked and unchecked exception types are treated just the same. Notice that that the JVM spec doesn't even mention checkedness in the section on exceptions.
So, as seen at runtime, the method can throw any exception. And as stated in the language spec:
Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N to the the type parameters of M, the same formal parameter types.
public class A extends Exception {....}
public class B extends A {....}
public class C extends RuntimeException {....}
Given the method signature A bar(B q) throws C, which of the following will not compile?
A.
A m() throws C {
return bar(new B());
}
B.
m() {
return bar(new B());
}
C. All of the above will compile.
The answer is C. There might be a typo with B, not sure.
I'm not understanding this question, conceptually, what's it asking, etc.
I get A is a superclass of B, and C is alone as a RuntimeException, so it's not checked at compile time?
And I get the inside of the method has to be a B time exception, which works in both answers.
Could someone help explain why both of these compile?
C is a kind of runtime exception. You don't need to declare a runtime exception, and they are ignored by the compiler.
Here's a good explanation to get started.
Declaring an exception doesn't mean there will necessarily be an exception. It just means that we should be prepared for the possiblility an exception is thrown.
Choice B will not compile, but not because of the exception. It will not compile because there is no return type. Choice A has declared a return of type A.
I have recently discovered and blogged about the fact that it is possible to sneak a checked exception through the javac compiler and throw it where it mustn't be thrown. This compiles and runs in Java 6 and 7, throwing a SQLException without throws or catch clause:
public class Test {
// No throws clause here
public static void main(String[] args) {
doThrow(new SQLException());
}
static void doThrow(Exception e) {
Test.<RuntimeException> doThrow0(e);
}
static <E extends Exception> void doThrow0(Exception e) throws E {
throw (E) e;
}
}
The generated bytecode indicates that the JVM doesn't really care about checked / unchecked exceptions:
// Method descriptor #22 (Ljava/lang/Exception;)V
// Stack: 1, Locals: 1
static void doThrow(java.lang.Exception e);
0 aload_0 [e]
1 invokestatic Test.doThrow0(java.lang.Exception) : void [25]
4 return
Line numbers:
[pc: 0, line: 11]
[pc: 4, line: 12]
Local variable table:
[pc: 0, pc: 5] local: e index: 0 type: java.lang.Exception
// Method descriptor #22 (Ljava/lang/Exception;)V
// Signature: <E:Ljava/lang/Exception;>(Ljava/lang/Exception;)V^TE;
// Stack: 1, Locals: 1
static void doThrow0(java.lang.Exception e) throws java.lang.Exception;
0 aload_0 [e]
1 athrow
Line numbers:
[pc: 0, line: 16]
Local variable table:
[pc: 0, pc: 2] local: e index: 0 type: java.lang.Exception
The JVM accepting this is one thing. But I have some doubts whether Java-the-language should. Which parts of the JLS justify this behaviour? Is it a bug? Or a well-hidden "feature" of the Java language?
My feelings are:
doThrow0()'s <E> is bound to RuntimeException in doThrow(). Hence, no throws clause along the lines of JLS §11.2 is needed in doThrow().
RuntimeException is assignment-compatible with Exception, hence no cast (which would result in a ClassCastException) is generated by the compiler.
All this amounts to exploiting the loophole that an unchecked cast to a generic type is not a compiler error. Your code is explicitly made type-unsafe if it contains such an expression. And since the checking of checked exceptions is strictly a compile-time procedure, nothing will break in the runtime.
The answer from the authors of Generics would most probably be along the lines of "If you are using unchecked casts, it's your problem".
I see something quite positive in your discovery—a break out of the stronghold of checked exceptions. Unfortunately, this can't turn existing checked-exception-poisoned APIs into something more pleasant to use.
How this can help
At a typical layered application project of mine there will be a lot of boilerplate like this:
try {
... business logic stuff ...
}
catch (RuntimeException e) { throw e; }
catch (Exception e) { throw new RuntimeException(e); }
Why do I do it? Simple: there are no business-value exceptions to catch; any exception is a symptom of a runtime error. The exception must be propagated up the call stack towards the global exception barrier. With Lukas' fine contribution I can now write
try {
... business logic stuff ...
} catch (Exception e) { throwUnchecked(e); }
This may not seem like much, but the benefits accumulate after repeating it 100 times throughout the project.
Disclaimer
In my projects there is high discipline regarding exceptions so this is a nice fit for them. This kind of trickery is not something to adopt as a general coding principle. Wrapping the exception is still the only safe option in many cases.
This example is documented in The CERT Oracle Secure Coding Standard for Java which documents several non compliant code examples.
Noncompliant Code Example (Generic Exception)
An unchecked cast of a generic type with parameterized exception declaration can also result in unexpected checked exceptions. All such casts are diagnosed by the compiler unless the warnings are suppressed.
interface Thr<EXC extends Exception> {
void fn() throws EXC;
}
public class UndeclaredGen {
static void undeclaredThrow() throws RuntimeException {
#SuppressWarnings("unchecked") // Suppresses warnings
Thr<RuntimeException> thr = (Thr<RuntimeException>)(Thr)
new Thr<IOException>() {
public void fn() throws IOException {
throw new IOException();
}
};
thr.fn();
}
public static void main(String[] args) {
undeclaredThrow();
}
}
This works because RuntimeException is child class of Exception and you can not convert any class extending from Exception to RuntimeException but if you cast like below it will work
Exception e = new IOException();
throw (RuntimeException) (e);
The case you are doing is same as this.
Because this is explicit type casting this call will result in ClassCastException however compiler is allowing it.
Because of Erasure however in your case there is no cast involved and hence in your scenario it does not throw ClassCastException
In this case there is no way for compiler to restrict the type conversion you are doing.
However if you change method signature to below it will start complaining about it.
static <E extends Exception> void doThrow0(E e) throws E {
Well, that's one of multiple ways to raise a check exception as if it were unchecked. Class.newInstance() is another, Thread.stop(Trowable) a deprecated one.
The only way for the JLS not to accept this behavior is if the runtime (JVM) will enforce it.
As to were it is specified: It isn't. Checked and unchecked exceptions behave the same. Checked exceptions simply require a catch block or a throws clause.
Edit: Based on the discussion in the comments, a list-based example exposing the root cause: Erasure
public class Main {
public static void main(String[] args) {
List<Exception> myCheckedExceptions = new ArrayList<Exception>();
myCheckedExceptions.add(new IOException());
// here we're tricking the compiler
#SuppressWarnings("unchecked")
List<RuntimeException> myUncheckedExceptions = (List<RuntimeException>) (Object) myCheckedExceptions;
// here we aren't any more, at least not beyond the fact that type arguments are erased
throw throwAny(myUncheckedExceptions);
}
public static <T extends Throwable> T throwAny(Collection<T> throwables) throws T {
// here the compiler will insert an implicit cast to T (just like your explicit one)
// however, since T is a type variable, it gets erased to the erasure of its bound
// and that happens to be Throwable, so a useless cast...
throw throwables.iterator().next();
}
}
JLS 11.2:
For each checked exception which is a possible result, the throws
clause for the method (§8.4.6) or constructor (§8.8.5) must mention
the class of that exception or one of the superclasses of the class of
that exception (§11.2.3).
This clearly indicates doThrow must have Exception in it's throws clause. Or, as downcasting (Exception to RuntimeException) is involved, the check must be done that Exception IS RuntimeException, which should fail in example because the exception being cast is SQLException. So, ClassCastException should be thrown in runtime.
As of practical side, this java bug allows to create a hack unsafe for any standard exception handling code, like next:
try {
doCall();
} catch (RuntimeException e) {
handle();
}
The exception will go up without being handled.
I don't think it can be disputed that the JLS allows that code. The question is not whether that code should be legal. The compiler simply does not have enough information to issue an error.
The issue here with the code emitted when you call a generic-throwing method. The compiler currently inserts type casts after calling a generic-returning methods where the returned value will be immediately assigned to a reference.
If the compiler wanted, it could prevent the problem by silently surrounding all generic-throwing method invocations in a try-catch-rethrow fragment. Since the exception would be caught and assigned to a local variable, a type cast would be mandatory. So you would get a ClassCastException if it was not an instance of RuntimeException.
But the spec does not mandate anything special about generic-throwing methods. I believe that's an spec bug. Why not file a bug about that, so that it can be fixed or at least documented.
By the way, the ClassCastException would suppress the original exception, which can result in hard-to-find bugs. But that problem has a simple solution since JDK 7.