try catch机制非常好。那些觉得try catch不行的人,是他们自己的水平有问题,无法理解这种机制。并且这群人写代码不遵守规则,喜欢偷懒,这才造成try catch不好的错觉。

详细解释:

1.程序要健壮,必须要设计报错机制。

最古老,也是最常见的,比如:

bool CreateFile( );

//如果创建文件失败就返回false,否则返回true。

这种报错方式,显然不好。因为它没有给出产生错误的具体原因。

2.改进:一个函数或过程,会因为不同的原因产生错误,报错机制必须要把这些错误原因进行区分后,再汇报。

比如:

int CreateFile():

//如果创建成功就返回1.

//如果是因为没有权限,导致失败,返回-1。

//如果是因为文件已经存在,导致失败,返回-2。

//如果是因为创建文件发生超时,导致失败,返回-3。

这样看上去,比【1】要好些,至少指出了比较具体的失败原因,但是,还不够。

3.很多情况下,函数需要把详细的原因,用字符串的方式,返回:

class Result

{

....int State;//同【2】

....string ErrorMessage;//如果失败,这里将给出详细的信息,如果有可能,应该把建议也写上去。

}

Result CreateFile();

//如果创建成功,返回的Result,State为1,ErrorMessage为null。

//如果是因为没有权限,导致失败,返回的Result,State为-1,ErrorMessage为"用户【guest】没有权限在【C:\】这个目录下创建该文件。建议您向管理员申请权限,或者更换具有权限的用户。"。

//如果是因为文件已经存在,导致失败,返回的Result,State为-2,ErrorMessage为"文件【C:\abc.txt】已经存在。如果需要覆盖,请添加参数:arg_overwrite = true"。

//如果是因为创建文件发生超时,导致失败,返回的Result,State为-3,ErrorMessage为"在创建文件时超时,请使用chkdsk检查文件系统是否存在问题。"。

4.我个人推崇上面这种方式,完整,美观。但是这种流程,容易与正常的代码混在一起,不好区分开。因此,Java、C#等设计了try catch这一种特殊的方式:

void CreateFile()

//如果创建成功就不会抛出异常。

//如果是因为没有权限,导致失败,会抛出AccessException,这个Exception的Msg属性为"用户【guest】没有权限在【C:\】这个目录下创建该文件。建议您向管理员申请权限,或者更换具有权限的用户。"。

//如果是因为文件已经存在,导致失败,会抛出FileExistedException,这个Exception的Msg属性为"文件【C:\abc.txt】已经存在。如果需要覆盖,请添加参数:arg_overwrite = true"。

//如果是因为创建文件发生超时,导致失败,会抛出TimeoutException,这个Exception的Msg属性为"在创建文件时超时,请使用chkdsk检查文件系统是否存在问题。"。

可见,上述机制,实际上是用不同的Exception代替了【3】的State。

这种机制,在外层使用时:

try

{

....CreateFile( "C:\abc.txt" );

}

catch( AccessException e )

{

....//代码进入这里说明发生【没有权限错误】

}

catch( FileExistedException e )

{

....//代码进入这里说明发生【文件已经存在错误】

}

catch( TimeoutException e )

{

....//代码进入这里说明发生【超时错误】

}

对比一下【3】,其实这与【3】本质相同,只是写法不同而已。

5.综上,我个人喜欢【3】这类面向过程的写法。但很多喜欢面向对象的朋友,估计更喜欢【4】的写法。然而【3】与【4】都一样。这两种机制都是优秀的错误处理机制。

6.理论说完了,回到正题,题注问:为什么不用try catch?

答:这是因为,很多菜鸟,以及新手,他们是这样写代码的:

void CreateFile( )

//无论遇到什么错误,就抛一个 Exception,并且也不给出Msg信息。

这样的话,在外层只能使用:

try

{

....CreateFile( "C:\abc.txt" );

}

catch( Exception e )

{

....//代码进入这里说明发生错误

}

当出错后,只知道它出错了,并不知道是什么原因导致错误。这同【1】。

以及,即使CreateFile是按【4】的规则设计的,但菜鸟在外层是这样使用的:

try

{

....CreateFile( "C:\abc.txt" );

}

catch( Exception e )

{

....//代码进入这里说明发生错误

....throw Exception( "发生错误" )

}

这种情况下,如果这位菜鸟的同事,调用了这段代码,或者用户看到这个错误信息,也只能知道发生了错误,但并不清楚错误的原因。这与【1】是相同的。

出于这些原因,菜鸟的同事,以及用户,并没有想到,造成这个问题是原因菜鸟的水平太差,写代码图简单省事。他们却以为是try catch机制不行。

因此,这就导致了二逼同事,以及傻比用户,不建议用try catch。

通常try/catch适用于以下场景:

在代码中对可预见而又无法掌控的情况进行处理。比如在SOCKET BIND时发现端口已经被占用了、或者IO在打开文件时发现文件不存在,就需要在catch中做适当的处理避免程序crash掉;

将问题向更上一层面传递,将处理权让渡给caller。假如你写了个ORM FRAMEWORK,在delete的时候发现外键关联删除失败,FRAMEWORK不能擅自替上层的代码决定该怎么办,于是只好把DB的报的错误原样(或者加层外衣)throw出来,调用者根据业务需要选择处理方式;

除此之外,所有问题应该由程序员主动判断,就地解决。在规模比较大的软件中,定义自己的Exception体系并正确、克制地使用try/catch,可以让代码变得易读易维护还美观。

传递给上层来解决例子如下:

void handlearray(int a[]) throws Npe

{

if(a==null)

throw new Npe();

a[0]……//处理部分

}

上层:

try{

handlearray(a);

}catch(E… e)

{

//对a进行处理。

}

这时候传入数组为空,这个错误不是你当前这个函数所能处理的,只能是抛给上层,也就是生成这个数组,或者能对这个数组负责的那部分代码,让上层去处理,上层去try cacth,并在catch中对异常处理,类库中类似的像文件io的时候很多读写类都会抛出FileNotFoundException,也是一个道理,当上层给我一个找不到的文件,那在我的io类中肯定无法处理你这个异常,只能抛到给我这个文件的那一层,让那一层的代码对这个问题进行反应。

当然有些时候不需要,比如:

void makearray(int a[])

{

a=new int[];

……//生成部分

if(a==null)

……//处理部分,此处一般不用抛异常,直接可以在这一层处理掉。

}

像这个就不一样了,因为这次发生的问题是在我这一层代码所能控制之内的,所以我直接把问题处理掉就好了,没必要给上层了。

为什么讲“正确”并“克制”地使用?因为有些又蠢又懒的程序员喜欢这么干:

将函数所有代码都放到try{}之中,哪怕 int i = 1这种赋值的都不放过。然后在catch里输出一个错误信息就万事大吉。这样看起来是很省心哇,不用动脑子去分析哪里可能发生什么错误,反正所有错误都在catch的掌控之中;

用try/catch来控制流程。举个简单的例子,假设有这么个要求:

将字符串转换成数字,并返回该数字的绝对值,如果出错了就返回-1. 于是乎,就能见到类似下面代码的奇葩做法:

int parse_number(const char* s){

try{

return abs(atoi(s));

}catch(Exception){

return -1;

}

}

这多省事儿,不用考虑s是不是NULL、不用考虑s是不是包含非数字的字符、不用考虑s是不是超出int的取值范围...我是个优秀的程序员耶~~,我的代码好简洁。

try/catch和errno可以结合起来使用,二者不是非此即彼的关系,比如在某些场景下,可以将不确定的错误简化归纳为固定的errno输出,调用者直接检查返回的errno即可,简化了代码,也减轻了负担。比如某函数,成功返回0,失败返回-1:

int foo(double d){

try{

do_something(d);

return 0;

}catch(Exception){

return -1;

}

}

void bar(double d){

int result = foo(d);

if(result == -1) return;

do_next_steps();

}

三、细节

Java中try,catch,finally的用法

Java异常处理的组合方式:

1.try+catch

运行流程:运行到try块中,如果有异常抛出,则转到catch块去处理。然后执行catch块后面的语句

2.try+catch+finally

运行流程:运行到try块中,如果有异常抛出,则转到catch块,catch块执行完毕后,执行finally块的代码,再执行finally块后面的代码。

如果没有异常抛出,执行完try块,也要去执行finally块的代码。然后执行finally块后面的语句

网上有很多人探讨Java中异常捕获机制try...catch...finally块中的finally语句是不是一定会被执行?很多人都说不是,当然他们的回答是正确的,经过我试验,至少有两种情况下finally语句是不会被执行的:

(1)try语句没有被执行到,如在try语句之前就返回了,这样finally语句就不会执行,这也说明了finally语句被执行的必要而非充分条件是:相应的try语句一定被执行到。

(2)在try块中有System.exit(0);这样的语句,System.exit(0);是终止Java虚拟机JVM的,连JVM都停止了,所有都结束了,当然finally语句也不会被执行到。

四、检查型异常和非检查型异常

Paste_Image.png

上图摘自Java 进阶 之 检查型异常与非检查型异常

直接继承 Exception 的异常,属于检查型异常,必须用try语句块进行处理或者把异常交给上级方法处理总之就是必须写代码处理它。如IOException,SQLException

继承自Runtime Exception或 Error 的是非检查型异常,可以不用捕获

1、throws出现在方法函数头;而throw出现在函数体。

2、throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象。

3、两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

java try catch 例子_java try catch相关推荐

  1. java try catch 例子_Java异常处理综合例子(try、catch、finally、throws、throw)

    Java异常处理综合例子(try.catch.finally.throws.throw) 佟强 2009年11月4日 http://blog.csdn.net/microtong package cn ...

  2. java catch 抛出异常_java - 在catch和最后claus中抛出异常

    java - 在catch和最后claus中抛出异常 关于大学的Java问题,有这段代码: class MyExc1 extends Exception {} class MyExc2 extends ...

  3. java线程安全例子_Java总结篇系列:Java多线程(三)

    本文主要接着前面多线程的两篇文章总结Java多线程中的线程安全问题. 一.一个典型的Java线程安全例子 1 public classThreadTest {2 3 public static voi ...

  4. java try 的用法_java try(){}catch(){}自动释放资源及用法

    java语言中try(){}catch(){}的用法介绍.介绍了通常的try-catch的用法以及 try-with-resources 的用法. 1.try{} catch(){}的用法 通常try ...

  5. java线程同步例子_JAVA线程同步实例教程

    线程是Java程序设计里非常重要的概念,本文就以实例形式对此加以详细解读.具体分析如下: 首先,线程加锁有什么用处呢?举个例子:比如你现在有30000块大洋在银行存着,现在你到银行取钱,当你输入密码完 ...

  6. java reactor模式例子_JAVA BIO,NIO,Reactor模式总结

    传统同步阻塞I/O(BIO) 在NIO之前编写服务器使用的是同步阻塞I/O(Blocking I/O).下面是一个典型的线程池客服端服务器示例代码,这段代码在连接数急剧上升的情况下,这个服务器代码就会 ...

  7. python try catch语句_Java try catch语句

    在 Java 中通常采用 try catch 语句来捕获异常并处理.语法格式如下: try { 逻辑代码块1; } catch(ExceptionType e) { 处理代码块1; } 在以上语法中, ...

  8. java自定义监听器例子_Java使用自定义注解实现为事件源绑定事件监听器操作示例...

    本文实例讲述了Java使用自定义注解实现为事件源绑定事件监听器操作.分享给大家供大家参考,具体如下: 一 定义注解 import java.lang.annotation.*; import java ...

  9. java编程的例子_java编程实例

    1:编写程序,判断给定的某个年份是否是闰年. 闰年的判断规则如下:(1)若某个年份能被4整除但不能被100整除,则是闰年.(2)若某个年份能被400整除,则也是闰年. import java.util ...

最新文章

  1. ONNX MLIR方法
  2. 后端数据操作超时_数据分析在知乎商业质量保障中的初步实践
  3. Golang中调用“方法”的简单理解
  4. P1991-无线通讯网【最小生成树,瓶颈生成树】
  5. C++学习之路 | PTA乙级—— 1020 月饼 (25分)(精简)
  6. bootstraptable查看详情_bootstrap-table前端实现多条件时间段查询数据
  7. python+selenium处理chrome显示通知弹框
  8. Python|520表白神器
  9. Linux常用命令--uname
  10. Mac双开微信(2种方法)、Win多开微信
  11. CRC检验码计算——C语言(CRC8/16/32)
  12. 微信小程序 组件传值(二) triggerEvent 子传父
  13. als算法参数_推荐算法之ALS
  14. 博弈论的一些基础知识(参考网络资料,学习总结,很好,分享并保存)
  15. 面试攻略!Java 基础面试 100 问
  16. matlab三相短路电流计算程序_三相短路电流计算
  17. CSS3转换属性—transform之translate、rotate、scale函数详解
  18. 【开播3.5小时,观看近5万人,3天销量第一】2021企业数字化转型落地高峰论坛暨《数字化转型方法论》新书发布会大获成功
  19. 如何使用ExternalContext类(一)
  20. 错误:找不到或无法加载主类 X.X.X.Application,解决办法

热门文章

  1. log4net保存到数据库系列二:独立配置文件中配置log4net
  2. 没有人能阻止程序员将电脑上的一切搬到网页上
  3. 动态规划--Leetcode64.最小路径和
  4. java 线程变量put_Java线程(篇外篇):线程本地变量ThreadLocal
  5. python数据归一化
  6. MATALB(三)绘图命令
  7. JavaSE——常用类库(String类)
  8. 怎样在MySQL中显示中文,而不出现乱码?
  9. 不带头结点的单链表的建立
  10. CV中的经典网络模型