学编程,来源栈;先学习,再交钱
当前系列: 编程语言 修改讲义

什么是异常?

@想一想@:方法getGrade(score)可以处理0-100分之间的成绩(score),但当该方法被调用时传入的参数score是-60或者150时,咋办?

  1. 程序还该不该继续运行?
  2. 是否该将这种情况予以通告?

我们之前的方案是 1. return 和 2. 控制台输出。

if(score<0 || score> 100){
	console.log("成绩不能小于0或大于100");  
	return; 
}

但:

  • 不是所有的程序都有控制台的,不是所有用户都开控制台读取信息的
  • return不能终止后续代码的执行,产生难以预计的后

所以现代语言为我们提供了一种更完善的异常(exception的直译)处理机制

在上述例子中,score在0-100之间,就是;超出这个范围,就是

例外;一般情况以外的人(或事物)


运行时错误

异常又被称之为:运行时错误,对应Java/C#等编译型语言的编译时错误。

因为它们总是在运行时才会被抛出,编译时就会被发现的错误不会是异常。



抛出异常

需要使用关键字:throw

throw "成绩不能小于0或大于100";    //或者
throw Error("成绩不能小于0或大于100");

演示:

  1. throw之后的语句无法执行,无论是getGrade()里面的,还是getGrade()调用之后的:中断程序执行
  2. 控制台显示异常信息(含堆栈信息)

理解“抛出”:

  1. 正常情况下,成绩只能是在0-100分;或者说,当前方法只能处理0-100分的成绩
  2. 现在输入的成绩超出了这个范围,当前方法也不知道怎么回事,该怎么处理……

所以只能抛出异常,交由“调用者”处理。

对比:error&bug

当我们的代码写得有问题的时候,比如:

console.loog();

也会出现异常(错误)信息。

所以很多同学就会觉得:

  1. 错误(error)是不是就是(被抛出来)的异常啊?答案:是的。
  2. 有异常被抛出来,就说明程序有bug;好的代码,根本就不会有异常被抛出。答案:不一定。

但实际上,异常只是提示可能有bug。

有些异常是:

  • 我们无法预料的,比如:读取文件读不到,写文件磁盘满了……
  • 预料到了也难以/无法处理的,比如:getGrade(score)方法本来只能处理0-100的成绩,你-20我咋办?

另外:

  • 有bug也不一定抛异常:很多bug是逻辑错误,比如找到的不是最大值
  • 反过来,异常的使用能够减少bug!


为什么需要异常?

牢记:错误暴露得越早越好!

延伸:在工作中也一样,很多同学习惯性“埋雷”。

  • 学习中:遇到问题不问(我三番五次的强调,没用)
  • 工作中:甲方提交过来的需求/老大交代下来的任务,没弄明白/超出能力范围之外,不反馈不汇报

闷着头瞎搞……

@想一想@:最终的结果是咋样的,你应该怎么做?

发现问题,就应该:

  • 中断执行
  • 立即汇报

把问题扼杀于萌芽状态。

为什么我们说强类型的编译时检查非常棒,为什么我们要单元测试TDD,为什么我们要防御式编程……都是基于这个原因。


try...catch...finally

被抛出的异常,(如果没有被处理/捕获)会直接传递给它的调用者,再由调用者传递给它的调用者,...,直到程序最顶层调用,被称之为未处理(unhandled)异常,程序崩溃

为了避免程序崩溃,我们需要try...catch来捕获异常:

try{
    let grade = getGrade(-80);
}catch{    //
    console.log("给用户提示:你的输入有错");
}

如果try块里面的代码报了异常,就会进入catch块(异常被捕获);否则,跳过catch块。

演示:

  • throw过后的代码不会被执行
  • 但catch过后的代码还是会被执行

注意区分:正常的log输出和未处理异常造成error

catch中还可以再抛出异常

}catch(e){    //e里面包含了所有异常信息
	console.log("给用户提示:你的输入有错");  //log
	throw e;    //把异常信息再抛出去
}

有时候我们希望一段代码无论有无异常,都要执行(主要用于清理资源,比如关闭文件流/数据库连接等),这就需要使用finally

//在try...catch后面接上:
}finally{
	console.log("总是要执行");
}

演示:

  • getGrade()抛异常和不抛异常
  • try块中有return;
  • catch中再次抛出异常
finally都被执行。


使用注意事项

异常会带来较大的资源开销(性能损耗),所以要尽可能避免异常被抛出(注意:不是不写throw exception的代码)

一种典型的错误就是把try...catch做为分支判断条件:if有异常,就catch……

比如我们上面的代码就是不对(好)的,更好的写法应该是:

if(score>100 || score<0){
	console.log("给用户提示:你的输入有错");  //log
	return;
}

@想一想@:这里的if判断和getGrade()里的if判断,重复了么?

没有重复,这叫做“各扫门前雪”。要明白:实际开发不是你现在这样所有代码一个人写,会有分工……

学习笔记
源栈学历
键盘敲烂,月薪过万作业不做,等于没学

作业

觉得很 ,不要忘记分享哟!

任何问题,都可以直接加 QQ群:273534701

在当前系列 编程语言 中继续学习:

多快好省!前端后端,线上线下,名师精讲

  • 先学习,后付费;
  • 不满意,不要钱。
  • 编程培训班,我就选源栈

更多了解 加:

QQ群:273534701

答疑解惑,远程debug……

B站 源栈-小九 的直播间

写代码要保持微笑 (๑•̀ㅂ•́)و✧

公众号:源栈一起帮

二维码