Java try-with-resource 实现由编译器完成
Java try-with-resource implementation done by compiler
我想知道,当异常发生时,try with resource 语句如何设法在进入 catch 块之前关闭资源。
当异常发生时,执行立即跳转到 catch 块。所以实际上 try-with-resource 关闭资源的地方。
为了更好地理解它是如何工作的,我决定看看编译器是如何实现它的。我写了下面的代码并编译了它。
public class Test
{
public static void main(final String[] args) {
//I used same JDK for compilation and execution.
System.out.println("Java version: " + System.getProperty("java.version") + "\n");
try(CloseMe me = new CloseMe();
CloseMeToo meToo = new CloseMeToo()){
System.out.println("trying");
throw new Exception("try failed");
} catch(Exception e) {
System.out.println("failed");
System.out.println("\n");
System.out.println(e.getMessage());
System.out.println(e.getSuppressed()[0].getMessage());
System.out.println(e.getSuppressed()[1].getMessage());
}
}
}
class CloseMe implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("me closing!");
throw new Exception("don't close me :o");
}
}
class CloseMeToo implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("meToo closing!");
throw new Exception("don't close me too :O");
}
}
输出
Java version: 15.0.1
trying
meToo closing!
me closing!
failed
try failed
don't close me too :O
don't close me :o
然后我去了 www.javadecompilers.com 并尝试了那里的反编译器。两个反编译器给出了不错的结果:CFR 0.150 和 Fernflower。
CFR 最易读和完整,因此将其张贴在这里。
public class Test
{
public static void main(final String[] args) throws Throwable{
System.out.println("Java version: " + System.getProperty("java.version") + "\n");
try {
Throwable throwable = null;
Object var2_4 = null; //<-- where this variable is used?
try {
CloseMe me = new CloseMe();
try {
CloseMeToo meToo = new CloseMeToo();
try {
System.out.println("trying");
throw new Exception("try failed");
}
catch (Throwable throwable2) {
throwable = throwable2; //<-- I put this line to make it work
if (meToo != null) {
meToo.close();
}
throw throwable2;
}
}
catch (Throwable throwable3) {
if (throwable == null) {
throwable = throwable3;
} else if (throwable != throwable3) {
throwable.addSuppressed(throwable3);
}
if (me != null) {
me.close();
}
throw throwable;
}
}
catch (Throwable throwable4) {
if (throwable == null) {
throwable = throwable4;
} else if (throwable != throwable4) {
throwable.addSuppressed(throwable4);
}
throw throwable;
}
}
catch (Exception e) {
System.out.println("failed");
System.out.println("\n");
System.out.println(e.getMessage());
System.out.println(e.getSuppressed()[0].getMessage());
System.out.println(e.getSuppressed()[1].getMessage());
}
}
}
我知道反编译器有局限性。理想的反编译器会给我同样的 try-with-resource,我不会看到这些细节。所以没关系。
我的问题是:
- 在上面的反编译代码中,变量
var2_4
没有被使用。此外,我必须添加一行以使其像 try-with-resource 一样工作。我认为代码不完整。如果有,可以add/explain缺件吗?
- 如果任何了解字节码的人将 class 文件翻译成准确的 java 代码,那就太好了。或者给我指点,告诉我在哪里可以获得完成这项工作的工具。
谢谢!
try-with-resources 的行为在 Java Language Specification, section 14.20.3. try-with-resources.
中完全 记录
具体说明如下简版问题代码:
try (CloseMe me = new CloseMe(); CloseMeToo meToo = new CloseMeToo()) {
System.out.println("trying");
} catch (Exception e) {
System.out.println("failed");
}
首先转换为:
try {
try (CloseMe me = new CloseMe(); CloseMeToo meToo = new CloseMeToo()) {
System.out.println("trying");
}
} catch (Exception e) {
System.out.println("failed");
}
然后到:
try {
final CloseMe me = new CloseMe();
Throwable #primaryExc1 = null;
try (CloseMeToo meToo = new CloseMeToo()) {
System.out.println("trying");
} catch (Throwable #t) {
#primaryExc1 = #t;
throw #t;
} finally {
if (me != null) {
if (#primaryExc1 != null) {
try {
me.close();
} catch (Throwable #suppressedExc) {
#primaryExc1.addSuppressed(#suppressedExc);
}
} else {
me.close();
}
}
}
} catch (Exception e) {
System.out.println("failed");
}
然后到:
try {
final CloseMe me = new CloseMe();
Throwable #primaryExc1 = null;
try {
final CloseMeToo meToo = new CloseMeToo()
Throwable #primaryExc2 = null;
try {
System.out.println("trying");
catch (Throwable #t) {
#primaryExc2 = #t;
throw #t;
} finally {
if (meToo != null) {
if (#primaryExc2 != null) {
try {
meToo.close();
} catch (Throwable #suppressedExc) {
#primaryExc2.addSuppressed(#suppressedExc);
}
} else {
meToo.close();
}
}
}
} catch (Throwable #t) {
#primaryExc1 = #t;
throw #t;
} finally {
if (me != null) {
if (#primaryExc1 != null) {
try {
me.close();
} catch (Throwable #suppressedExc) {
#primaryExc1.addSuppressed(#suppressedExc);
}
} else {
me.close();
}
}
}
} catch (Exception e) {
System.out.println("failed");
}
我想知道,当异常发生时,try with resource 语句如何设法在进入 catch 块之前关闭资源。
当异常发生时,执行立即跳转到 catch 块。所以实际上 try-with-resource 关闭资源的地方。
为了更好地理解它是如何工作的,我决定看看编译器是如何实现它的。我写了下面的代码并编译了它。
public class Test
{
public static void main(final String[] args) {
//I used same JDK for compilation and execution.
System.out.println("Java version: " + System.getProperty("java.version") + "\n");
try(CloseMe me = new CloseMe();
CloseMeToo meToo = new CloseMeToo()){
System.out.println("trying");
throw new Exception("try failed");
} catch(Exception e) {
System.out.println("failed");
System.out.println("\n");
System.out.println(e.getMessage());
System.out.println(e.getSuppressed()[0].getMessage());
System.out.println(e.getSuppressed()[1].getMessage());
}
}
}
class CloseMe implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("me closing!");
throw new Exception("don't close me :o");
}
}
class CloseMeToo implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("meToo closing!");
throw new Exception("don't close me too :O");
}
}
输出
Java version: 15.0.1
trying
meToo closing!
me closing!
failed
try failed
don't close me too :O
don't close me :o
然后我去了 www.javadecompilers.com 并尝试了那里的反编译器。两个反编译器给出了不错的结果:CFR 0.150 和 Fernflower。 CFR 最易读和完整,因此将其张贴在这里。
public class Test
{
public static void main(final String[] args) throws Throwable{
System.out.println("Java version: " + System.getProperty("java.version") + "\n");
try {
Throwable throwable = null;
Object var2_4 = null; //<-- where this variable is used?
try {
CloseMe me = new CloseMe();
try {
CloseMeToo meToo = new CloseMeToo();
try {
System.out.println("trying");
throw new Exception("try failed");
}
catch (Throwable throwable2) {
throwable = throwable2; //<-- I put this line to make it work
if (meToo != null) {
meToo.close();
}
throw throwable2;
}
}
catch (Throwable throwable3) {
if (throwable == null) {
throwable = throwable3;
} else if (throwable != throwable3) {
throwable.addSuppressed(throwable3);
}
if (me != null) {
me.close();
}
throw throwable;
}
}
catch (Throwable throwable4) {
if (throwable == null) {
throwable = throwable4;
} else if (throwable != throwable4) {
throwable.addSuppressed(throwable4);
}
throw throwable;
}
}
catch (Exception e) {
System.out.println("failed");
System.out.println("\n");
System.out.println(e.getMessage());
System.out.println(e.getSuppressed()[0].getMessage());
System.out.println(e.getSuppressed()[1].getMessage());
}
}
}
我知道反编译器有局限性。理想的反编译器会给我同样的 try-with-resource,我不会看到这些细节。所以没关系。
我的问题是:
- 在上面的反编译代码中,变量
var2_4
没有被使用。此外,我必须添加一行以使其像 try-with-resource 一样工作。我认为代码不完整。如果有,可以add/explain缺件吗? - 如果任何了解字节码的人将 class 文件翻译成准确的 java 代码,那就太好了。或者给我指点,告诉我在哪里可以获得完成这项工作的工具。
谢谢!
try-with-resources 的行为在 Java Language Specification, section 14.20.3. try-with-resources.
中完全 记录具体说明如下简版问题代码:
try (CloseMe me = new CloseMe(); CloseMeToo meToo = new CloseMeToo()) {
System.out.println("trying");
} catch (Exception e) {
System.out.println("failed");
}
首先转换为:
try {
try (CloseMe me = new CloseMe(); CloseMeToo meToo = new CloseMeToo()) {
System.out.println("trying");
}
} catch (Exception e) {
System.out.println("failed");
}
然后到:
try {
final CloseMe me = new CloseMe();
Throwable #primaryExc1 = null;
try (CloseMeToo meToo = new CloseMeToo()) {
System.out.println("trying");
} catch (Throwable #t) {
#primaryExc1 = #t;
throw #t;
} finally {
if (me != null) {
if (#primaryExc1 != null) {
try {
me.close();
} catch (Throwable #suppressedExc) {
#primaryExc1.addSuppressed(#suppressedExc);
}
} else {
me.close();
}
}
}
} catch (Exception e) {
System.out.println("failed");
}
然后到:
try {
final CloseMe me = new CloseMe();
Throwable #primaryExc1 = null;
try {
final CloseMeToo meToo = new CloseMeToo()
Throwable #primaryExc2 = null;
try {
System.out.println("trying");
catch (Throwable #t) {
#primaryExc2 = #t;
throw #t;
} finally {
if (meToo != null) {
if (#primaryExc2 != null) {
try {
meToo.close();
} catch (Throwable #suppressedExc) {
#primaryExc2.addSuppressed(#suppressedExc);
}
} else {
meToo.close();
}
}
}
} catch (Throwable #t) {
#primaryExc1 = #t;
throw #t;
} finally {
if (me != null) {
if (#primaryExc1 != null) {
try {
me.close();
} catch (Throwable #suppressedExc) {
#primaryExc1.addSuppressed(#suppressedExc);
}
} else {
me.close();
}
}
}
} catch (Exception e) {
System.out.println("failed");
}