Java 从try中捕获对象构造过程中的错误,并将资源与主体分开 总结
我有一个可关闭类型,Java 从try中捕获对象构造过程中的错误,并将资源与主体分开 总结,java,try-with-resources,autocloseable,Java,Try With Resources,Autocloseable,我有一个可关闭类型,CloseableClass,它可以在它的构造函数、方法中甚至在close中抛出一个IOError。我想使用try-with-resources,但在构建过程中处理错误的方式与在使用过程中处理错误的方式不同(使用包括清理)。更好的是,我想编写可维护的代码 假设您希望构造一个closeable类实例,并将其与try with resources语句一起使用。它可以在其构造函数和try with resources主体中使用的方法中抛出IOException: import j
CloseableClass
,它可以在它的构造函数、方法中甚至在close
中抛出一个IOError。我想使用try-with-resources,但在构建过程中处理错误的方式与在使用过程中处理错误的方式不同(使用包括清理)。更好的是,我想编写可维护的代码
假设您希望构造一个closeable类实例,并将其与try with resources语句一起使用。它可以在其构造函数和try with resources主体中使用的方法中抛出
IOException
:
import java.io.Closeable;
import java.io.IOException;
import java.util.Random;
public class CloseableClass implements Closeable {
public CloseableClass() throws IOException {
if (new Random().nextBoolean()) {
throw new IOException();
}
}
public void internetStuff() throws IOException {
if (new Random().nextBoolean()) {
throw new IOException();
}
}
public void close() throws IOException {
if (new Random().nextBoolean()) {
throw new IOException();
}
}
public static void main(String[] args) {
try (CloseableClass closeable = new CloseableClass()) {
closeable.internetStuff();
}
catch (IOException e) {
System.out.println("Bad error!");
}
}
}
假设您希望分别处理构造函数和主体中抛出的错误。有没有一种受支持的方法可以做到这一点?在Python中,我将执行以下操作:
try:
closeable = CloseableClass()
except IOException:
print("Constructor error")
return
try:
with closeable:
closeable.internet_stuff()
except IOException:
print("Body error")
但在Java中,如果不为对象指定第二个名称,则不能:
CloseableClass closeable_;
try {
closeable_ = new CloseableClass();
}
catch (IOException e) {
System.out.println("Constructor error!");
return;
}
try (CloseableClass closeable = closeable_) {
closeable.internetStuff();
}
catch (IOException e) {
System.out.println("Body error!");
}
有人告诉我,这是“无法维护的代码”,主要是因为使用了closeable\uu
,我对此表示同意。我希望避免使用try finally,因为这样您在模拟它时会遇到更糟糕的问题:
CloseableClass closeable;
try {
closeable = new CloseableClass();
}
catch (IOException e) {
System.out.println("Constructor error!");
return;
}
try {
closeable.internetStuff();
}
catch (IOException e) {
try {
closeable.close();
}
catch (IOException ignore) {
// Already dealing with this
}
System.out.println("Body error!");
}
finally {
try {
closeable.close();
}
catch (IOException e) {
System.out.println("Body error!");
}
}
注意,这需要对close
的第二次调用成为no-op,测试类不遵守该操作(注意AutoCloseable
不需要,尽管Closeable
需要)。如果close
不能抛出,但抛出的次数不多,这会稍微好一点
基本上问题是
可以抛出关闭
- 在处理
之前关闭,以防止打印两次IOException
“正文错误!”
- 如何使用try with resources中的多个初始值设定项还不清楚
- 你最终还是复制了代码
catch
块中的close()
,因为最后将始终执行块。如果在catch
块中使用类似于System.exit()的调用终止JVM,则只能在catch
块中使用close()
。通常,您将从catch
时钟向调用者抛出Exception
,但您将在最后执行清理阻塞大部分时间
使用资源进行尝试更好,但您可以使用抛出的异常的类型和描述来破译错误的内容和位置
编辑
据我所知,我建议:
1) 尝试使用资源:
try(Resource resource = new Resource()){
// use resource.
}catch(Exception e){
// handle exception.
// OR better to throw exception to caller.
throw e;
}
2) 传统风格:
Resource resource = null;
try{
resource = new Resource();
// use resource
}catch(Exception e){
// handle exception.
// OR better to throw exception to caller.
throw e;
} finally {
if(resource != null){
try{
resource.close();
} catch(Exception e){
// most of time you wont or cant do anything here.
}
}
}
一种解决方案是定义一种方法,将初始化错误封装在自定义异常类型中,然后使用该方法确定错误发生的时间
private CloseableClass createCloseable() throws CloseableCreateException{
try {
return new CloseableClass();
} except (IOException e) {
throw new CloseableCreateException(e);
}
}
另一个简单但有点不雅观的解决方案是使用布尔标志:
boolean init = true;
try (CloseableClass closeable = new CloseableClass()) {
init = false;
closeable.internetStuff();
} catch (IOException e) {
if (init) {
System.out.println("Constructor error!");
} else {
System.out.println("Body error!");
}
}
是的,但是如果我不尝试在捕获中关闭,我最终会冒打印“Body error!”
两次的风险(如果尝试{…}
和关闭
抛出)。我真正的用例,Socket
似乎抛出了很多裸露的IOException
s,因此我不能只选择更具体的异常来捕获。您仍然有可能打印“Body Error!”,因为catch块将打印,并且可能最终也会被阻止。记住,finally块将始终执行,无论您是从try或catch返回异常,还是从这些返回,但finally块都将始终执行。使用您添加的代码,我如何从类的构造函数和try
的主体中区分错误?从异常的类型和描述中。像创建FileReader
一样,可能会抛出FileNotFoundException
,这是来自文件读取器的构造函数,而不是来自readig file。如果无法区分异常,则需要尝试{}catc(){}每行代码。是的,您也可以在try中关闭资源,并在try中使其为null,以防止最后再次关闭。但我更喜欢最后收尾。
boolean init = true;
try (CloseableClass closeable = new CloseableClass()) {
init = false;
closeable.internetStuff();
} catch (IOException e) {
if (init) {
System.out.println("Constructor error!");
} else {
System.out.println("Body error!");
}
}