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.
Related
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 am currently trying to understand how Java infers the type of lambda expressions. I can illustrate with an example:
Writing:
producer.send(record, new Callback() {
public void onCompletion(RecordMetadata metadata, Exception exception) {
if (exception == null) {
logger.info("Received new metadata"
);
} else {
logger.error("Error while producing " + exception);
My IDE suggested that can be re-written to:
producer.send(record, (metadata, exception) -> {
if (exception == null) {
logger.info("Received new metadata"
);
} else {
logger.error("Error while producing " + exception);
}
Which made me think: How does the compiler guess the types for metadata and exception?
Reading through some articles like this, I found that:
Java 8 also introduced Lambda Expressions. Lambda Expressions do not
have an explicit type. Their type is inferred by looking at the
target type of the context or situation. The Target-Type of an
expression is the data type that the Java Compiler expects depending
on where the expression appears.
I am not sure what is meant here by "context or situation". I am looking for a better technical explanation of how the compiler infers types. And when would I need to explicitly tag types.
producer.send is a method that accepts a record and a Callback, and Callback has exactly one abstract method, which accepts a RecordMetadata and an Exception. Therefore, if the compiler sees a lambda as the second argument to producer.send, it must be implementing the method Callback.onCompletion, and it must have two arguments, with the first a RecordMetadata and the second an Exception.
The point being: it's inferred from the type of the method that you're passing the lambda to.
Adding a point to Louis Wasserman's answer.
The same lambda expression can be applied to different target types.
private static void predicate(Predicate<String> predicate) {
predicate.test("abcd");
}
private static void function(Function<String, Boolean> function) {
function.apply("abcd");
}
predicate(s -> s.length() > 5);
function(s -> s.length() > 5);
The lambda expression s -> s.length() > 5 can both be a Predicate and a Function based on the context.
Considering method references,
private static void consumer(Consumer<String> consumer) {
consumer.accept("abcd");
}
private static void function2(Function<String, Integer> function) {
function.apply("abcd");
}
consumer(String::length);
function2(String::length);
You might be surprised to find that we can use String::length as a Consumer. Think of it as ignoring the return type. But expanding the method reference won't work
consumer(s -> {
return s.length();
});
For the code below, why do I get this compile time error:
The method overloadedMethod(IOException) is ambiguous for the type Test.
public class Test {
public static void main(String[] args) {
Test test = new Test();
test.overloadedMethod(null);
}
void overloadedMethod(IOException e) {
System.out.println("1");
}
void overloadedMethod(FileNotFoundException e) {
System.out.println("2");
}
void overloadedMethod(Exception e) {
System.out.println("3");
}
void overloadedMethod(ArithmeticException e) {
System.out.println("4");
}
}
Both FileNotFoundException and ArithmeticException are in the same level in java object hierarchy. Compiler confused to choose most specific method, Since both method are eligible for invocation.
Even Compiler can't choose most specific method, if there are multiple object hierarchies. So removing either of FileNotFoundException or ArithmeticException won't solve the problem.
From JLS 15.12.2.5
If more than one member method is both accessible and applicable to a
method invocation, it is necessary to choose one to provide the
descriptor for the run-time method dispatch. The Java programming
language uses the rule that the most specific method is chosen.
The informal intuition is that one method is more specific than
another if any invocation handled by the first method could be passed
on to the other one without a compile-time type error.
You have four versions of overloadedMethod that accept parameters of type IOException, FileNotFoundException, Exception and ArithmeticException.
When you call
test.overloadedMethod(null);
the JVM cannot know which version of the method you are intending to call. That is why the ambiguous error.
You need to be more specific on which version you want to call. You can do that by casting the parameter:
test.overloadedMethod((IOException)null);
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
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.