This question already has answers here:
Java 8 method reference unhandled exception
(6 answers)
Closed 1 year ago.
I have two functions throwing Exception:
public void foo() throws Exception {
// something
}
public void bar() throws Exception {
// something
}
If I combine those function calls using curly braces in lambda expression, it needs try/catch to handle exception.
public void someFunction() throws Exception {
someList.forEach(e -> {
// Show compile error and need try/catch
foo();
bar();
});
}
However, if I combine in for-loop, it is fine.
public void someFunction() throws Exception {
for (SomeElement e : someList) {
foo();
bar();
}
}
I though try/catch needed because of new closure created (using bracket), but in for-loop, it does not require.
I solved it by just using for loop, but I wonder why it happens.
List#forEach expects a Consumer.
Consumer is a (single-abstract-method) interface that looks like this (simplified):
#FunctionalInterface
public interface Consumer<T>{
void accept(T t);
}
As you see, accept does not throw any checked exceptions.
The lambda expression is an implementation of that interface so it cannot throw any exceptions, no matter what the other code does.
Related
Bear with me, the introduction is a bit long-winded but this is an interesting puzzle.
I have this code:
public class Testcase {
public static void main(String[] args){
EventQueue queue = new EventQueue();
queue.add(() -> System.out.println("case1"));
queue.add(() -> {
System.out.println("case2");
throw new IllegalArgumentException("case2-exception");});
queue.runNextTask();
queue.add(() -> System.out.println("case3-never-runs"));
}
private static class EventQueue {
private final Queue<Supplier<CompletionStage<Void>>> queue = new ConcurrentLinkedQueue<>();
public void add(Runnable task) {
queue.add(() -> CompletableFuture.runAsync(task));
}
public void add(Supplier<CompletionStage<Void>> task) {
queue.add(task);
}
public void runNextTask() {
Supplier<CompletionStage<Void>> task = queue.poll();
if (task == null)
return;
try {
task.get().
whenCompleteAsync((value, exception) -> runNextTask()).
exceptionally(exception -> {
exception.printStackTrace();
return null; });
}
catch (Throwable exception) {
System.err.println("This should never happen...");
exception.printStackTrace(); }
}
}
}
I am trying to add tasks onto a queue and run them in order. I was expecting all 3 cases to invoke the add(Runnable) method; however, what actually happens is that case 2 gets interpreted as a Supplier<CompletionStage<Void>> that throws an exception before returning a CompletionStage so the "this should never happen" code block gets triggered and case 3 never runs.
I confirmed that case 2 is invoking the wrong method by stepping through the code using a debugger.
Why isn't the Runnable method getting invoked for the second case?
Apparently this issue only occurs on Java 10 or higher, so be sure to test under this environment.
UPDATE: According to JLS §15.12.2.1. Identify Potentially Applicable Methods and more specifically JLS §15.27.2. Lambda Body it seems that () -> { throw new RuntimeException(); } falls under the category of both "void-compatible" and "value-compatible". So clearly there is some ambiguity in this case but I certainly don't understand why Supplier is any more appropriate of an overload than Runnable here. It's not as if the former throws any exceptions that the latter does not.
I don't understand enough about the specification to say what should happen in this case.
I filed a bug report which is visible at https://bugs.openjdk.java.net/browse/JDK-8208490
The problem is that there are two methods:
void fun(Runnable r) and void fun(Supplier<Void> s).
And an expression fun(() -> { throw new RuntimeException(); }).
Which method will be invoked?
According to JLS §15.12.2.1, the lambda body is both void-compatible and value-compatible:
If the function type of T has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2).
If the function type of T has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2).
So both methods are applicable to the lambda expression.
But there are two methods so java compiler needs to find out which method is more specific
In JLS §15.12.2.5. It says:
A functional interface type S is more specific than a functional interface type T for an expression e if all of the following are true:
One of the following is:
Let RS be the return type of MTS, adapted to the type parameters of MTT, and let RT be the return type of MTT. One of the following must be true:
One of the following is:
RT is void.
So S (i.e. Supplier) is more specific than T (i.e. Runnable) because the return type of the method in Runnable is void.
So the compiler choose Supplier instead of Runnable.
First, according to §15.27.2 the expression:
() -> { throw ... }
Is both void-compatible, and value-compatible, so it's compatible (§15.27.3) with Supplier<CompletionStage<Void>>:
class Test {
void foo(Supplier<CompletionStage<Void>> bar) {
throw new RuntimeException();
}
void qux() {
foo(() -> { throw new IllegalArgumentException(); });
}
}
(see that it compiles)
Second, according to §15.12.2.5 Supplier<T> (where T is a reference type) is more specific than Runnable:
Let:
S := Supplier<T>
T := Runnable
e := () -> { throw ... }
So that:
MTs := T get() ==> Rs := T
MTt := void run() ==> Rt := void
And:
S is not a superinterface or a subinterface of T
MTs and MTt have the same type parameters (none)
No formal parameters so bullet 3 is also true
e is an explicitly typed lambda expression and Rt is void
It appears that when throwing an Exception, the compiler chooses the interface which returns a reference.
interface Calls {
void add(Runnable run);
void add(IntSupplier supplier);
}
// Ambiguous call
calls.add(() -> {
System.out.println("hi");
throw new IllegalArgumentException();
});
However
interface Calls {
void add(Runnable run);
void add(IntSupplier supplier);
void add(Supplier<Integer> supplier);
}
complains
Error:(24, 14) java: reference to add is ambiguous
both method add(java.util.function.IntSupplier) in Main.Calls and method add(java.util.function.Supplier) in Main.Calls match
Lastly
interface Calls {
void add(Runnable run);
void add(Supplier<Integer> supplier);
}
compiles fine.
So weirdly;
void vs int is ambiguous
int vs Integer is ambiguous
void vs Integer is NOT ambiguous.
So I figure something is broken here.
I have sent a bug report to oracle.
First things first:
The key point is that overloading methods or constructors with
different functional interfaces in the same argument position causes
confusion. Therefore, do not overload methods to take different
functional interfaces in the same argument position.Joshua Bloch, - Effective Java.
Otherwise, you'll need a cast to indicate the correct overloading:
queue.add((Runnable) () -> { throw new IllegalArgumentException(); });
^
The same behavior is evident when using an infinite loop instead of a runtime exception:
queue.add(() -> { for (;;); });
In the cases shown above, the lambda body never completes normally, which adds to the confusion: which overload to choose (void-compatible or value-compatible) if the lambda is implicitly typed? Because in this situation both methods become applicable, for example you can write:
queue.add((Runnable) () -> { throw new IllegalArgumentException(); });
queue.add((Supplier<CompletionStage<Void>>) () -> {
throw new IllegalArgumentException();
});
void add(Runnable task) { ... }
void add(Supplier<CompletionStage<Void>> task) { ... }
And, like stated in this answer - the most specific method is chosen in case of ambiguity:
queue.add(() -> { throw new IllegalArgumentException(); });
↓
void add(Supplier<CompletionStage<Void>> task);
At the same time, when the lambda body completes normally (and is void-compatible only):
queue.add(() -> { for (int i = 0; i < 2; i++); });
queue.add(() -> System.out.println());
the method void add(Runnable task) is chosen, because there is no ambiguity in this case.
As stated in the JLS §15.12.2.1, when a lambda body is both void-compatible and value-compatible, the definition of potential applicability goes beyond a basic arity check to also take into account the presence and shape of functional interface target types.
I wrongly considered this a bug, but it appears to be correct according to §15.27.2. Consider:
import java.util.function.Supplier;
public class Bug {
public static void method(Runnable runnable) { }
public static void method(Supplier<Integer> supplier) { }
public static void main(String[] args) {
method(() -> System.out.println());
method(() -> { throw new RuntimeException(); });
}
}
javac Bug.java
javap -c Bug
public static void main(java.lang.String[]);
Code:
0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
5: invokestatic #3 // Method add:(Ljava/lang/Runnable;)V
8: invokedynamic #4, 0 // InvokeDynamic #1:get:()Ljava/util/function/Supplier;
13: invokestatic #5 // Method add:(Ljava/util/function/Supplier;)V
16: return
This happens with jdk-11-ea+24, jdk-10.0.1, and jdk1.8u181.
zhh's answer led me to find this even simpler test case:
import java.util.function.Supplier;
public class Simpler {
public static void main(String[] args) {
Supplier<Integer> s = () -> { throw new RuntimeException(); };
}
}
However, duvduv pointed out §15.27.2, in particular, this rule:
A block lambda body is value-compatible if it cannot complete normally (§14.21) and every return statement in the block has the form return Expression;.
Thus, a block lambda is trivially value-compatible even if it contains no return statement at all. I would have thought, because the compiler needs to infer its type, that it would require at least one return Expression;. Holgar and others have pointed out that this is not necessary with ordinary methods such as:
int foo() { for(;;); }
But in that case the compiler only needs to ensure there is no return that contradicts the explicit return type; it doesn't need to infer a type. However, the rule in the JLS is written to allow the same freedom with block lambdas as with ordinary methods. Perhaps I should have seen that sooner, but I did not.
I filed a bug with Oracle but have since sent an update to it referencing §15.27.2 and stating that I believe my original report to be in error.
This question already has answers here:
Exception handling : throw, throws and Throwable
(8 answers)
Closed 7 years ago.
Hi I wanted to know what the difference and similarities between the two variations of the kind of the same methods would be.
public string test(String value)
throw new testException();
and
public abstract String test(String value) throw new testException;
please forgive me if my syntax is wrong.
public abstract String test(String value) throw new testException;
does not make sense. The closest thing you can do is write
public abstract String test(String value) throws testException;
which indicates that test is a method that could throw a testException. If testException is not a RuntimeException, then it must be declared like that. But adding throws testException to the method signature only says that the method could throw that exception, it doesn't actually do the throwing.
In java each method should indicate if they are throwing exceptions or not by using this syntax:
public String test(String value) throws testException
{
//your code here
//at some point you will throw the exception like this:
throw new testException();
}
if you are using abstract method, the method signature only needs to contain the throws expression but when you implement the method you need to add the throw statement in the body of the method.
This question already has answers here:
What does the arrow operator, '->', do in Java?
(6 answers)
Closed last year.
Today I met part of weird code which I do not understand.
What can mean something like this ()->
for example
method( ()-> System.out.println("Hello") );
another question is, what is an output of String:
[AB][CD]*EF+(X/Y)
of course there were not any instance of A, B etc.But I there were answers like
ABCDEFX,
ACEFXX,
ACEFXA,
I do not remember them
Can anybody help me?
Suppose you have an interface that declares one method:
public static interface MyFunctionalInterface {
void m1();
}
And you have a method that receives an object of that type as a parameter:
public void method(MyFunctionalInterface i) { ... }
You can implement that interface and use it immediately using anonymous inner classes like this:
method( new MyFunctionalInterface() {
public void m1() {
System.out.println("Hello");
}
});
In Java 8 you can replace that with a lambda expression such as the one you showed:
method( () -> System.out.println("Hello"); );
The empty parameters represent the m1() method, with no parameters.
Suppose the functional interface you were using had a method with one parameter (if your method had the form method2(ActionListener s) { ... } for example), then you would use:
method2( e -> System.out.println("Hello"); );
which would be the same as doing this:
method2( new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Hello");
}
});
There are many tutorials about Lambda expressions in Java 8. This one is a good quick-start.
class MyException extends Exception { }
class Tire {
void doStuff() { } // #4
}
public class Retread extends Tire {
public static void main(String[] args) {
new Retread().doStuff();
}
// insert code here
System.out.println(7/0);
}
And given the following four code fragments:
void doStuff() {
void doStuff() throws MyException {
void doStuff() throws RuntimeException {
void doStuff() throws ArithmeticException {
When fragments 1 - 4 are added, independently, at line 10, which are true? (Choose all that apply.)
A. None will compile
B. They will all compile
C. Some, but not all, will compile
D. All of those that compile will throw an exception at runtime
E. None of those that compile will throw an exception at runtime
F. Only some of those that compile will throw an exception at runtime
Answer: C and D are correct. An overriding method cannot throw checked exceptions that are broader than those thrown by the overridden method. However an overriding method can throw RuntimeExceptions not thrown by the overridden method. A, B, E,and Fare incorrect based on the above. (Objective 2.4)
I dont get what the BoldItalic marking is saying in this context. The overriding method(#4) doesnt throw any exception so how do we know if the one (in this case MyException) we add to the overridden method ( option 2) is broader than the overriding method. How does Arithmetic exception runs with no error. How is it not broader than the dont-know-which-exception in the overriding method.
You override method void doStuff() { } which throws no exception with one of the options. So let's look at them, one by one:
void doStuff() { .. }
This one is okay, it throws no Exception like the base method.
void doStuff() throws MyException { .. }
This one won't compile. MyException is a checked exception because it extends Exception and the base method doesn't declare any checked exceptions at all.
void doStuff() throws RuntimeException { ... }
This will work, because RuntimeException is an unchecked exception.
void doStuff() throws ArithmeticException { ... }
This will work too, because ArithmeticException is a RuntimeException, so unchecked.
void doStuff() { }
is not throwing any checked exception .
so the overriding method should also not throw any checked exception,
although it can throw a runtime exception(which need not to be mentioned be declaration).
If the overridden method doesn't throw a checked exception, overriding method cannot throw, too. Throwing checked exceptions means nothing for compile time. You can throw any subclass of Runtime Exception without saying that this methods throws blah blah.
Runtime exceptions are generally bugs and development mistakes, such as nullpointerexception and arithmeticexception. You need to check those kind of pointers/values before sending them to a method. Otherwise, the program crashes.
Hovewer, you have nothing to do with checked exceptions except try/catch. They can have many causes such as connection error, file system error, operating system permissions, etc..
Inside Method A, there is method B. Method B throws exception, but method A compiled even it does not catch exception or throws exception, could it be possible?
Method B is something like as below:
MethodB() throws SomeException{
if(Some)
doneSomething
return
else if(some)
donesomethingElse
return
throw SomeException
}
If the SomeException extends RuntimeException. Then you don't need to catch it even if the signature looks like that.
Also note that you can just remove the throws SomeException in that case. Read more here.
Yes, there are some unchecked exception, who might not be caught / rethrown.
Look at this tutorial - Unchecked Exceptions.
Even if SomeException is a checked exception, this can happen due to separate compilation.
Suppose you write a class:
public class B {
public static void foo() {
}
}
Then a class that calls it:
public class A {
public static void main(String[] args) {
B.foo();
}
}
Then say:
javac A.java
java A
All is fine. Now change B:
public class B {
public static void foo() throws java.io.IOException {
throw new java.io.IOException();
}
}
And this time just compile B before running:
javac B.java
java A
You get:
Exception in thread "main" java.io.IOException
at B.foo(B.java:4)
at A.main(A.java:4)
In the real world this happens when individual .jar files are updated after they've been modified by maintainers who don't understand the problems caused by adding more throws clauses.