继承和 Try-With-Resources
Inheritance and Try-With-Resources
假设有两个 类 实现 AutoCloseable
接口如下:
public class Closing1 implements AutoCloseable {
private boolean closed;
@Override
public void close() throws Exception {
if (closed) {
throw new Exception("Closed Already");
}
this.closed = true;
System.out.println("Closing1 closed");
}
public boolean isClosed() {
return closed;
}
}
和
public class Closing2 implements AutoCloseable {
private Closing1 cl1;
public Closing2(Closing1 cl1) {
this.cl1 = cl1;
}
@Override
public void close() throws Exception {
if(!cl1.isClosed()) {
throw new Exception("Closing1 not closed");
}
System.out.println("Closing2 closed");
}
}
我发现尝试使用资源的所有变体都会导致异常!我在这里遗漏了什么,还是 TWR 的设计方式?
try(Closing1 c1 = new Closing1();Closing2 c2 = new Closing2(c1)){
System.out.println("Done");
} //Exception while auto closing C2
或
try(Closing1 c1 = new Closing1();Closing2 c2 = new Closing2(c1)){
System.out.println("Done");
c1.close();
} // exception while auto closing c1
Try-with-resources 将按照声明的相反顺序关闭资源。这意味着 c2.close()
将首先被调用,这将抛出您编写的异常。
先从 try-with-resources 开始,https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
正如第一个示例所示:
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
人们不一定会为链中的所有内容命名。
除非您明确需要 c1 来做某事(关闭除外),否则在现实生活中您的代码段应该看起来像
try(Closing2 c2 = new Closing2(new Closing1())){
System.out.println("Done");
}
而且您肯定不会在 try 块中调用 c1.close()
,因为根本没有 c1。
记住这一点,因为包含的 c1 没有关闭而从 c2 抛出异常,这是完全错误的,实际上 c2 拥有 Closing1 对象并且应该在其上调用 close()
:
class Close1 implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("Closing c1");
}
}
class Close2 implements AutoCloseable {
Close1 c1;
Close2(Close1 c1) {
this.c1=c1;
}
@Override
public void close() throws Exception {
System.out.print("Closing c1 from c2: ");
c1.close();
System.out.println("Closing c2");
}
}
void test() {
System.out.println("Before try block");
try(Close2 c2=new Close2(new Close1())) {
System.out.println("In try block");
}
catch(Exception ex) {
System.out.println("Exception: "+ex);
}
finally {
System.out.println("In finally block");
}
System.out.println("After try block");
}
然而,如果有人给 c1 命名,它会被关闭两次,这就是幂等性发挥作用的地方,正如有人已经建议的那样:
System.out.println("Before try block");
try(Close1 c1 = new Close1(); Close2 c2 = new Close2(c1)){
System.out.println("In try block");
}
catch(Exception ex){
System.out.println("Exception: "+ex);
}
finally{
System.out.println("In finally block");
}
System.out.println("After try block");
正如已经提到的 BufferedReader
,这是它具有的 close()
方法:
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
cb = null;
}
}
}
如果它有 in
,它会被关闭并清空(在 finally 块中,所以即使发生异常也会发生),并且所有这些都在线程安全块中。 (cb
只是一个字符数组,它也会被空化,稍微简化了垃圾收集器的工作)。由于 finally 块中的所有内容都为空,因此对同一方法的任何额外调用都不会执行任何操作(除了暂时同步锁)。
假设有两个 类 实现 AutoCloseable
接口如下:
public class Closing1 implements AutoCloseable {
private boolean closed;
@Override
public void close() throws Exception {
if (closed) {
throw new Exception("Closed Already");
}
this.closed = true;
System.out.println("Closing1 closed");
}
public boolean isClosed() {
return closed;
}
}
和
public class Closing2 implements AutoCloseable {
private Closing1 cl1;
public Closing2(Closing1 cl1) {
this.cl1 = cl1;
}
@Override
public void close() throws Exception {
if(!cl1.isClosed()) {
throw new Exception("Closing1 not closed");
}
System.out.println("Closing2 closed");
}
}
我发现尝试使用资源的所有变体都会导致异常!我在这里遗漏了什么,还是 TWR 的设计方式?
try(Closing1 c1 = new Closing1();Closing2 c2 = new Closing2(c1)){
System.out.println("Done");
} //Exception while auto closing C2
或
try(Closing1 c1 = new Closing1();Closing2 c2 = new Closing2(c1)){
System.out.println("Done");
c1.close();
} // exception while auto closing c1
Try-with-resources 将按照声明的相反顺序关闭资源。这意味着 c2.close()
将首先被调用,这将抛出您编写的异常。
先从 try-with-resources 开始,https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
正如第一个示例所示:
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
人们不一定会为链中的所有内容命名。
除非您明确需要 c1 来做某事(关闭除外),否则在现实生活中您的代码段应该看起来像
try(Closing2 c2 = new Closing2(new Closing1())){
System.out.println("Done");
}
而且您肯定不会在 try 块中调用 c1.close()
,因为根本没有 c1。
记住这一点,因为包含的 c1 没有关闭而从 c2 抛出异常,这是完全错误的,实际上 c2 拥有 Closing1 对象并且应该在其上调用 close()
:
class Close1 implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("Closing c1");
}
}
class Close2 implements AutoCloseable {
Close1 c1;
Close2(Close1 c1) {
this.c1=c1;
}
@Override
public void close() throws Exception {
System.out.print("Closing c1 from c2: ");
c1.close();
System.out.println("Closing c2");
}
}
void test() {
System.out.println("Before try block");
try(Close2 c2=new Close2(new Close1())) {
System.out.println("In try block");
}
catch(Exception ex) {
System.out.println("Exception: "+ex);
}
finally {
System.out.println("In finally block");
}
System.out.println("After try block");
}
然而,如果有人给 c1 命名,它会被关闭两次,这就是幂等性发挥作用的地方,正如有人已经建议的那样:
System.out.println("Before try block");
try(Close1 c1 = new Close1(); Close2 c2 = new Close2(c1)){
System.out.println("In try block");
}
catch(Exception ex){
System.out.println("Exception: "+ex);
}
finally{
System.out.println("In finally block");
}
System.out.println("After try block");
正如已经提到的 BufferedReader
,这是它具有的 close()
方法:
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
cb = null;
}
}
}
如果它有 in
,它会被关闭并清空(在 finally 块中,所以即使发生异常也会发生),并且所有这些都在线程安全块中。 (cb
只是一个字符数组,它也会被空化,稍微简化了垃圾收集器的工作)。由于 finally 块中的所有内容都为空,因此对同一方法的任何额外调用都不会执行任何操作(除了暂时同步锁)。