Java风格:正确处理异常 [英] Java Style: Properly handling exceptions

查看:92
本文介绍了Java风格:正确处理异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



假设你有一个例子:

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

还有两个子类FileData,它从一些指定的文件中读取数据,StaticData ,它只返回一些预定义的常量数据。



现在,在读取文件时,可能会在FileData中抛出IOException,但StaticData将永远不会抛出。大多数风格指南都建议在调用堆栈中传播一个Exception,直到有足够的上下文可用来有效地处理它。



但是我真的不想添加一个throws子句为抽象的read()方法。为什么?因为数据和使用它的复杂机器对文件一无所知,它只是知道数据。此外,可能还有其他Data子类(并且更多的)永远不会抛出异常并且无瑕疵地提供数据。另一方面,IOException是必需的,因为if该磁盘是不可读的(或一些这样的)错误必须抛出。所以我看到的唯一出路就是抓住IOException并抛出一些RuntimeException。



这是正确的哲学吗?

解决方案

你是对的。



异常应该在使用的相同的抽象级别。这就是为什么自从java 1.4 Throwable支持异常链接。对于使用数据库的服务或对于存储不可知的服务,无需抛出FileNotFoundException。



可能是这样的: / p>

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

class DataFile extends Data {
public String read()throws DataUnavailableException {
if(!this.file.exits()){
抛出新的DataUnavailableException(无法读取,文件);
}

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


class DataMemory extends Data {
public String read() {
//一切都在内存中执行。没有例外。
}
}

class DataWebService extends Data {
public string read()throws DataUnavailableException {
//连接到某些互联网服务
尝试{
...
} catch(UnknownHostException uhe){
throw new DataUnavailableException(uhe);
}
}
}

请记住,如果你程序中继承,您应该仔细设计具体的场景,并用这些场景测试实现。显然,如果编写通用库很难,因为你不知道如何使用它。但大多数时候,应用程序被限制在特定的域。你的新异常应该是运行时间还是被检查?



一般的规则是抛出运行时的编程错误并检查可恢复的条件。



如果可以通过编程正确地避免异常(如NullPointerException或IndexOutOfBounds)使用运行时



如果异常是由于某些外部资源失去了程序员的控制权(网络被关闭),并且有一些可以完成的事情(显示在5分钟或某些事情中重试的消息),则应使用检查的异常。



如果异常失去了程序员的控制,但是NOTHING可以完成,您可以使用RuntimeException。例如,您应该写入一个文件,但该文件已被删除,您无法重新创建它或重新尝试,但程序应该失败(没有什么可以做的)最可能的运行时。



查看有效Java中的这两个项目:




  • 使用检查的异常可恢复

  • 抛出适合于抽象的异常



I希望这有帮助。


I keep getting stuck conceptually on deciding an Exception-handling structure for my project.

Suppose you have, as an example:

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

And two subclasses FileData, which reads your data from some specified file, and StaticData, which just returns some pre-defined constant data.

Now, upon reading the file, an IOException may be thrown in FileData, but StaticData will never throw. Most style guides recommend propagating an Exception up the call stack until a sufficient amount of context is available to effectively deal with it.

But I don't really want to add a throws clause to the abstract read() method. Why? Because Data and the complicated machinery using it knows nothing about files, it just knows about Data. Moreover, there may be other Data subclasses (and more of them) that never throw exceptions and deliver data flawlessly.

On the other hand, the IOException is necessary, for if the disk is unreadable (or some such) an error must be thrown. So the only way out that I see is catching the IOException and throwing some RuntimeException in its place.

Is this the correct philosophy?

解决方案

You're right.

The exception should be at the same level of abstraction where is used. This is the reason why since java 1.4 Throwable supports exception chaining. There is no point to throw FileNotFoundException for a service that uses a Database for instance, or for a service that is "store" agnostic.

It could be like this:

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 );
           }
      }
 }

Bear in mind that if you program with inheritance in mind, you should design carefully for the specific scenarios and test implementations with those scenarios. Obviously if it is harder to code an general purpose library, because you don't know how is it going to be used. But most of the times applications are constrained to an specific domain.

Should your new exception be Runtime or Checked? It depends, the general rule is to throw Runtime for programming errors and checked for recoverable conditions.

If the exception could be avoided by programming correctly ( such as NullPointerException or IndexOutOfBounds ) use Runtime

If the exception is due to some external resource out of control of the programmer ( the network is down for instance ) AND there is something THAT could be done ( Display a message of retry in 5 mins or something ) then a checked exception should be used.

If the exception is out of control of the programmer, but NOTHING can be done, you could use a RuntimeException. For instance, you're supposed to write to a file, but the file was deleted and you cannot re-create it or re-try then the program should fail ( there is nothing you can do about it ) most likely with a Runtime.

See these two items from Effective Java:

  • Use checked exceptions for recoverable conditions and run-time exceptions for programming errors
  • Throw exceptions appropriate to the abstraction

I hope this helps.

这篇关于Java风格:正确处理异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆