Description
FULL PRODUCT VERSION :
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b105)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b47, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
Given a SAM interface that is declared to throw a generic exception, a method taking it as a parameter, and *in a different file* a call site where a lambda is passed to that method, then depending on whether the .java files are compiled with one javac command or separately, it either compiles or doesn't compile.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create the following files Foo.java and Bar.java
-- Foo.java:
import java.io.IOException;
class Foo {
public void compiles() throws IOException {
String result = Bar.tryRepeatedly(10, () -> {
throw new IOException("dummy exception");
});
}
public void doesNotCompile() {
String result = Bar.tryRepeatedly(10, () -> "result");
}
public void compilesButUndesirable() throws Throwable {
String result = Bar.tryRepeatedly(10, () -> "result");
}
}
--
-- Bar.java:
class Bar {
public static <T, E extends Throwable> T tryRepeatedly(int maxTries, Action<T, E> action) throws E {
return action.run();
}
}
interface Action<T, E extends Throwable> {
T run() throws E;
}
--
2. Run the following command:
javac Foo.java Bar.java
3. Remove all .class files generated by the previous command
4. Run this this sequence of commands:
javac Bar.java
javac Foo.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code should compile in both steps 2 and 4.
ACTUAL -
Step 4 fails to compile, even though step 2 succeeded:
$ javac Foo.java Bar.java
$ rm *.class
$ javac Bar.java
$ javac Foo.java
Foo.java:12: error: unreported exception Throwable; must be caught or declared to be thrown
String result = Bar.tryRepeatedly(10, () -> "result");
^
1 error
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
-- Foo.java:
import java.io.IOException;
class Foo {
public void compiles() throws IOException {
String result = Bar.tryRepeatedly(10, () -> {
throw new IOException("dummy exception");
});
}
public void doesNotCompile() {
String result = Bar.tryRepeatedly(10, () -> "result");
}
public void compilesButUndesirable() throws Throwable {
String result = Bar.tryRepeatedly(10, () -> "result");
}
}
--
-- Bar.java:
class Bar {
public static <T, E extends Throwable> T tryRepeatedly(int maxTries, Action<T, E> action) throws E {
return action.run();
}
}
interface Action<T, E extends Throwable> {
T run() throws E;
}
--
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
All affected call sites must declare to throw the most generic exception class, or the interface must be changed to not throw checked exceptions (and any lambdas will need to wrap checked exceptions into unchecked exceptions).
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b105)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b47, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
Given a SAM interface that is declared to throw a generic exception, a method taking it as a parameter, and *in a different file* a call site where a lambda is passed to that method, then depending on whether the .java files are compiled with one javac command or separately, it either compiles or doesn't compile.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create the following files Foo.java and Bar.java
-- Foo.java:
import java.io.IOException;
class Foo {
public void compiles() throws IOException {
String result = Bar.tryRepeatedly(10, () -> {
throw new IOException("dummy exception");
});
}
public void doesNotCompile() {
String result = Bar.tryRepeatedly(10, () -> "result");
}
public void compilesButUndesirable() throws Throwable {
String result = Bar.tryRepeatedly(10, () -> "result");
}
}
--
-- Bar.java:
class Bar {
public static <T, E extends Throwable> T tryRepeatedly(int maxTries, Action<T, E> action) throws E {
return action.run();
}
}
interface Action<T, E extends Throwable> {
T run() throws E;
}
--
2. Run the following command:
javac Foo.java Bar.java
3. Remove all .class files generated by the previous command
4. Run this this sequence of commands:
javac Bar.java
javac Foo.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code should compile in both steps 2 and 4.
ACTUAL -
Step 4 fails to compile, even though step 2 succeeded:
$ javac Foo.java Bar.java
$ rm *.class
$ javac Bar.java
$ javac Foo.java
Foo.java:12: error: unreported exception Throwable; must be caught or declared to be thrown
String result = Bar.tryRepeatedly(10, () -> "result");
^
1 error
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
-- Foo.java:
import java.io.IOException;
class Foo {
public void compiles() throws IOException {
String result = Bar.tryRepeatedly(10, () -> {
throw new IOException("dummy exception");
});
}
public void doesNotCompile() {
String result = Bar.tryRepeatedly(10, () -> "result");
}
public void compilesButUndesirable() throws Throwable {
String result = Bar.tryRepeatedly(10, () -> "result");
}
}
--
-- Bar.java:
class Bar {
public static <T, E extends Throwable> T tryRepeatedly(int maxTries, Action<T, E> action) throws E {
return action.run();
}
}
interface Action<T, E extends Throwable> {
T run() throws E;
}
--
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
All affected call sites must declare to throw the most generic exception class, or the interface must be changed to not throw checked exceptions (and any lambdas will need to wrap checked exceptions into unchecked exceptions).