Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/377.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java风格:正确处理异常_Java_Exception - Fatal编程技术网

Java风格:正确处理异常

Java风格:正确处理异常,java,exception,Java,Exception,我一直在概念上为我的项目决定一个异常处理结构 例如,假设您有: public abstract class Data { public abstract String read(); } 还有两个子类FileData,它从指定的文件读取数据,还有StaticData,它只返回一些预定义的常量数据 现在,在读取文件时,可能会在FileData中引发IOException,但StaticData永远不会引发IOException。大多数样式指南建议将异常向上传播到调用堆栈,直到有足够的上下文

我一直在概念上为我的项目决定一个异常处理结构

例如,假设您有:

public abstract class Data {
   public abstract String read();
}
还有两个子类FileData,它从指定的文件读取数据,还有StaticData,它只返回一些预定义的常量数据

现在,在读取文件时,可能会在FileData中引发IOException,但StaticData永远不会引发IOException。大多数样式指南建议将异常向上传播到调用堆栈,直到有足够的上下文可用以有效处理它

但我并不想在abstract read()方法中添加throws子句。为什么?因为数据和使用它的复杂机器对文件一无所知,它只知道数据。此外,可能还有其他数据子类(以及更多)从不抛出异常并完美地交付数据

另一方面,IOException是必要的,因为如果磁盘不可读(或类似),则必须抛出错误。因此,我看到的唯一出路是捕获IOException并在其位置抛出一些RuntimeException


这是正确的原理吗?

抛出
IOException
,该异常封装在一个适合于“
数据
”类的异常类型中。事实上,
read
方法并不总是能够提供数据,它可能应该指出原因。包装异常可能会扩展
RuntimeException
,因此不需要声明(尽管它应该被适当地记录在案)。

如果您没有明确声明
read()
可以引发异常,那么当它引发异常时,您会让开发人员大吃一惊

在您的特定情况下,我将捕获底层异常,并将它们作为新的异常类重新显示
DataException
DataReadException

您应该在abstract read()方法上声明某种异常。抽象类实际上是在声明一个接口——您已经从两个具体的子类中了解到,由于异常情况,实现很可能无法成功返回

因此,在abstract Data.read()方法中声明一些要抛出的异常是完全正确的。不要试图简单地声明它抛出IOException,因为它不应该绑定到特定实现的和(否则,您必须声明,如果您决定使用数据库读取子类,它也可以抛出SQLException,如果您有基于XML的读取器(使用SAX),则抛出SAXException,等等)。您需要自己的自定义异常,以在抽象级别充分捕获此异常—类似于上面推荐的DataException,或者如果这有意义,则可能重用同一包中现有的自定义异常。

您是对的

异常应该在使用的抽象级别上。这就是java 1.4 Throwable支持异常链接的原因。例如,对于使用数据库的服务,或者对于“存储”不可知的服务,没有必要抛出FileNotFoundException

可能是这样的:

public abstract class Data {
   public abstract String read() throws DataUnavailableException;
}

class DataFile extends Data { 
    public String read() throws DataUnavailableException {
        if( !this.file.exits() ) {
            throw new DataUnavailableException( "Cannot read from ", file );
         }

         try { 
              ....
         } catch( IOException ioe ) { 
             throw new DataUnavailableException( ioe );
         } finally {
              ...
         }
 }


class DataMemory extends Data { 
    public String read()  {
        // Everything is performed in memory. No exception expected.
    }
 }

 class DataWebService extends Data { 
      public string read() throws DataUnavailableException {
           // connect to some internet service
           try {
              ...
           } catch( UnknownHostException uhe ) {
              throw new DataUnavailableException( uhe );
           }
      }
 }
请记住,如果您在编程时考虑了继承,那么您应该针对特定场景进行仔细设计,并使用这些场景测试实现。显然,如果编写通用库比较困难,因为您不知道如何使用它。但大多数情况下,应用程序都局限于特定的域

您的新异常应该是运行时的还是检查的?这取决于具体情况,一般规则是为编程错误抛出运行时,并检查可恢复条件

如果可以通过正确编程避免异常(如NullPointerException或IndexOutOfBounds),请使用Runtime

如果异常是由于程序员无法控制某些外部资源造成的(例如,网络已关闭),并且可以执行某些操作(显示5分钟后重试的消息或其他操作),则应使用选中的异常

如果异常超出了程序员的控制,但什么也做不了,那么可以使用RuntimeException。例如,您应该写入一个文件,但该文件已被删除,您无法重新创建或重试,那么程序很可能会在运行时失败(对此您无能为力)

请参阅有效Java中的以下两项:

  • 对可恢复条件使用检查异常,对编程错误使用运行时异常
  • 抛出适合于抽象的异常

我希望这会有所帮助。

使用运行时异常,并在顶部使用爆炸式的“一网打尽”。一开始有点吓人,但一旦你习惯了就会好起来

在我的web应用程序中,抛出的所有内容都是运行时。几乎没有“throws”子句,在我真正能够(或想要)处理异常的地方只有catchblock。在最高级别,有一个catch-Throwable,它呈现一个technicall错误页面,并写入一个日志条目

Log4J邮件发送给我日志条目和它前面的10个日志条目。所以当客户打电话时,我通常已经知道有问题了


通过正确的(单元)测试和干净的编程,增加的清洁度和可读性超过了任何时候检查异常的损失。

我会让DataException也将IOException保存在其中,以便处理异常的级别可以在需要时向下钻取。Paul,您不需要显式地执行此操作-从Java 1.4开始,您可以使用initCause(Throwable)方法或通过实现包含Throwable作为参数的构造函数来链接异常。Java是否允许子类中的重写方法删除throws声明?如果是这样的话,如果您正在使用从不抛出的子类,则可以使用它们,而不必处理异常