Java异常处理(2)--异常处理机制及自定义异常

简介: Java异常处理(2)--异常处理机制及自定义异常

在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行x/y运算时,要检测分母为0,数据为空,输入的不是数据而是字符等。过多的if-else分支会导致程序的代码加长、臃肿,可读性差。因此采用异常处理机制。


Java采用的异常处理机制,是将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序简洁、优雅,并易于维护。


Java提供的是异常处理的抓抛模型。


3ed9eaaeab604d0b82dc7297dbc53edf.png


Java程序的执行过程中如出现异常,会生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。


异常对象的生成抛出:

①由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当

前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例

对象并抛出——自动抛出

②由开发人员手动创建:Exception exception = new ClassCastException();——创

建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样


446ecbf5010e4eaea22550f04cc25c72.png


如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处理。如果异常没有在调用者方法中处理,它继续被抛给这个调用方法的上层方法。这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常。如果一个异常回main()方法,并且main()也不处理,则程序运行终止。


Java异常处理的方式


方式一:try-catch-finally

方式二:throws + 异常类型


通过try-catch-finally(finally可选)方式


try{
  //可能出现异常的代码
}catch(异常类型1 变量名e){
  //处理异常的方式1
}catch(异常类型2 变量名e){
  //处理异常的方式2
}
......
finally{
  //一定会执行的代码
}


如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。比 如 : 可 以 用 ArithmeticException 类 作 为 参 数 的 地 方 , 就 可 以 用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。但不能是与ArithmeticException类无关的异常。NullPointerException(catch中的语句将不会执行)。


使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常, 就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配。一旦try中的异常对象匹配到某一个catch时, 就进入catch中进行异常的处理。处理完成,就跳出当前的try-catch结构(在没有写finally的情况)。继续执行其后的代码。


catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。

catch中的异常类型如果存在子父类关系,则要求子类一定声明在父类的上面,否则会报错。


异常对象处理(一般写在catch语句里面,如e.printStackTrace()):

①返回String的getMessage() ,获取异常信息。

②没有返回值的printStackTrace(),获取异常类名和异常信息,以及异常出现在程序中的位置。


在try结构中声明的变量,再出了try结构以后,就不能再被调用。


try-catch-finally结构可以嵌套。


使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。

开发中,由于运行时异常比较常见,所以我们通常不针对运行时异常编写try-catch-finally。而针对于编译时异常,一定要考虑异常的处理。


通过throws方式


"throws 异常类型"写在方法的声明处,指明此方法执行时,可能会抛出的异常类型。一旦当方法体执行时,出现异常,会在异常代码处生成一个异常类的对象,此对象满足throws后写的异常类型时,就会被抛出。异常代码后续的代码不再执行。


public void readFile(String file) throws FileNotFoundException {
  ......
  // 读文件的操作可能产生FileNotFoundException类型的异常
  FileInputStream fis = new FileInputStream(file);
  ......
}


try-catch-finally真正地将异常给处理掉了。

throws的方式只是将异常抛给了方法的调用者,并没有真正将异常处理掉。


重写方法不能抛出比被重写方法范围更大的异常类型。在多态的情况下,对methodA()方法的调用-异常的捕获按父类声明的异常处理。


public class A {
  public void methodA() throws IOException {
  ......
  }
}
public class B1 extends A {
  public void methodA() throws FileNotFoundException {
  ......
  }
}
public class B2 extends A {
  public void methodA() throws Exception { //报错
  ......
  }
}


如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式处理。


手动抛出(生成创建)异常(throw)


Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要使用人工创建并抛出。


首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运行环境)。例如:


IOException e = new IOException();
throw e;


或者直接


throw new IOException();


用户自定义异常类


一般地,用户自定义异常类都是RuntimeException的子类。

自定义异常类必须继承现有的异常类。

自定义异常类通常需要编写几个重载的构造器。

自定义异常需要提供serialVersionUID。

自定义的异常通过throw抛出。


例子


class MyException extends Exception {
  static final long serialVersionUID = 13465653435L;
  private int idnumber;
  public MyException(String message, int id) {
  super(message);
  this.idnumber = id;
  }
  public int getId() {
  return idnumber;
  }
}


public class MyExpTest {
  public void regist(int num) throws MyException {
  if (num < 0)
    throw new MyException("人数为负值,不合理", 3);
  else
    System.out.println("登记人数" + num);
  }
  public void manager() {
  try {
    regist(100);
  } catch (MyException e) {
    System.out.print("登记失败,出错种类" + e.getId());
  }
  System.out.print("本次登记操作结束");
  }
public static void main(String args[]) {
  MyExpTest t = new MyExpTest();
  t.manager();
  }
}


相关文章
|
3天前
|
Java
Java 异常处理下篇:11 个异常处理最佳实践
本文深入探讨了 Java 异常处理的最佳实践,包括早抛出晚捕获、只捕获可处理的异常、不要忽略捕获的异常、抛出具体检查性异常、正确包装自定义异常、记录或抛出异常但不同时执行、避免在 `finally` 块中抛出异常、避免使用异常进行流程控制、使用模板方法处理重复的 `try-catch`、尽量只抛出与方法相关的异常以及异常处理后清理资源。通过遵循这些实践,可以提高代码的健壮性和可维护性。
|
2天前
|
Java
Java异常捕捉处理和错误处理
Java异常捕捉处理和错误处理
8 1
|
4天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
12 2
|
3天前
|
Java 数据库连接
深入浅出Java异常处理
【10月更文挑战第33天】在Java编程的海洋中,异常处理就像是救生圈,它不仅能够挽救程序于水深火热之中,还能让代码更加优雅地面对意外。本文将带你领略Java异常处理的魅力,从基础概念到高级技巧,让你的程序在遇到问题时能够从容不迫,优雅地解决问题。
|
4天前
|
Java 开发者
Java中的异常处理:从基础到高级
【10月更文挑战第31天】在Java编程世界中,异常处理是一块基石,它确保了程序的健壮性和可靠性。本文将带你从异常处理的基本概念出发,通过实例展示如何在Java中捕获和处理异常,并深入探讨自定义异常、异常链以及如何使用try-with-resources语句优化资源管理。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧,帮助你编写更加稳定和易于维护的代码。
|
Java 程序员 数据库
java异常处理机制(try-catch-finally)
/* * 异常处理机制 * 1.分类:Error和Exception * Error错误是JVM自动报错的,程序员无法解决例如开数组过大int a[]=new int [1024*1024*1024]; * Exception错误时程序员要解决的问题,例如指针越界,零做除数 * 2.
795 0
|
11天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
1天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
1天前
|
安全 Java 编译器
Java多线程编程的陷阱与最佳实践####
【10月更文挑战第29天】 本文深入探讨了Java多线程编程中的常见陷阱,如竞态条件、死锁、内存一致性错误等,并通过实例分析揭示了这些陷阱的成因。同时,文章也分享了一系列最佳实践,包括使用volatile关键字、原子类、线程安全集合以及并发框架(如java.util.concurrent包下的工具类),帮助开发者有效避免多线程编程中的问题,提升应用的稳定性和性能。 ####
18 1
|
5天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
下一篇
无影云桌面