首页 > Java中的异常和返回值有什么区别?

Java中的异常和返回值有什么区别?

@xiao_264028 Java中的异常和返回值有什么区别?


从逻辑上讲,函数的返回值是它的求值结果,是“预期的”、“正常的”结束函数求值得到的结果,而异常是发成错误,函数求值无法正常进行的时候必须处理的情况。

举个例子,f(x) = abs(x)的导函数,在x>0的时候求值结果是1,在x<0的时候求值结果是-1,而在x==0的时候函数没有定义,可以理解为“异常”,因为是没有返回值的。


异常让对程序错误的处理更加简单:

1.异常带有stacktrace信息,能够帮助你更直接地定位到错误发生的位置;

2.异常可以“打断”代码的执行,而如果用返回值来实现就需要写一堆if/else;

3.让代码的语义更加清晰,例如一个查询方法要返回一个用户对象,通常会这样实现:

User queryUser() throws QueryException;

可以清晰的看出方法要返回的是什么:

如果没有异常的支持,则方法需要将是否处理成功的标识、错误消息、查询结果 一起返回,可能会写成这样:

QueryResult queryUser();

class QueryResult<T>{
     private String resultCode;
     private String resultMessage;
     private T resultObject;
}

上面的几位同学更多地从语言使用方面来说明返回值与异常的区别,都总结的差不多了,我就不再继续啰嗦了。下面我说说自己的看法,仅供参考:

  1. 异常与返回值最大的区别是程序执行序的不同。在一个方法执行体内部,返回值是表示一个方法按照既定的逻辑(内部包含顺序、分支、循环和乃至goto的跳转)执行完毕,退出当前层次的调用;而异常更像是一种longjump,使得方法跳出既定的逻辑,返回到上层调用者。这样,在一个包含多层嵌套调用的执行过程中,如果不同层次的调用在某些条件下需要相同的处理逻辑,异常就提供了一个很好的统一处理策略。

  2. 异常和返回值的执行开销不同。java是一个基于栈的语言,程序的执行是通过调用栈来完成的。在进入一个方法体的时候,会往当前线程调用栈push一个栈帧,该栈帧相当于构建了该方法执行的一个上下文(包含入参,局部变量等)。多个嵌套调用对应就会有多次push栈操作。返回值表示当前层次调用完毕,调用栈只需简单执行pop操作即可。如果是异常,则需要维持整个线程调用层次的栈信息,并依次上溯,判断调用链上的某个上层调用是否能catch该异常。从这点来说,异常的开销要大于返回值的执行开销,所以在编码的时候,不要随便抛出异常,确实是异常情况才考虑抛出异常。

以上2点是主要差别,从第2点可知异常在抛出时候会记录调用栈的信息,这个在Throwable的源码中可以体现。基于这点,有一个不常见但某些时候比较有用的用法,如下所示,用以跟踪代码执行路径,这个一般在一些测试框架中会出现。

public class Location {
  private Throwable t;
  ...

  Location() { t = new Exception(); }
  ...
  // 还可以根据需要过滤t的栈帧
}

这个真的要展开的话复杂了,简单说说吧。

异常,狭义上是Exception的子类,广义上说所有的Throwable都能算。是在程序发生业务逻辑的错误或者遇到意外情况时抛出的一个特殊的类,如果不被捕获(当然有些Error是不应该被捕获的),会导致当前线程立刻停止并且异常退出。

而返回值则是方法正常执行完毕时返回给上一级调用对象返回的一个对象,当然,可以无视。

讲得比较粗,可能也有错误之处。见谅。

【热门文章】
【热门文章】