非常全面的Java异常处理(全文干货,值得收藏)

一.初始Java异常

1、对异常的理解:异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)

2、Java程序在执行过程中所发生对异常事件可分为两类:

  • Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError和OOM。一般不编写针对性 的代码进行处理。
  • Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:
  • 空指针访问
  • 试图读取不存在的文件
  • 网络连接中断
  • 数组角标越界

3、运行时异常和编译时异常

运行时异常

  • 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。
  • 对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。

编译时异常

  • 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一 般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。
  • 对于这类异常,如果程序不处理,可能会带来意想不到的结果。

二.Error和Exception

1.Error

代码示例一:java.lang.OutOfMemoryError(堆溢出)

public class ErrorTest {
 public static void main(String[] args) {
 //堆溢出:java.lang.OutOfMemoryError
 Long[] arr = new Long[1024*1024*1024];
 }
}

运行结果:

代码示例二:java.lang.StackOverflowError(栈溢出)

public class ErrorTest {
 public static void main(String[] args) {

 //栈溢出:java.lang.StackOverflowError
 main(args);
 }
}

运行结果:

2.Exception(运行时异常和编译时异常)

运行时异常

 /* ******************以下是运行时异常****************** */
 //ArithmeticException
 @Test
 public void test1(){
 int num1 = 3;
 int num2 = 0;
 int num3 = 3 / 0;
 }

 //InputMismatchException
 @Test
 public void test2(){
 Scanner scanner = new Scanner(System.in);
 int i = scanner.nextInt();
 System.out.println(i);
 scanner.close();
 }

 //NumberFormatException
 @Test
 public void test3(){
 String str = "abcd";
 int num = Integer.parseInt(str);
 }

 //ClassCastException
 @Test
 public void test4(){
 Object obj = new Boolean(true);
 String str = (String)obj;
 }

 //IndexOutOfBoundsException
 @Test
 public void test5(){
 ArrayIndexOutOfBoundsException
 Byte[] bytes = new Byte[3];
 System.out.println(bytes[4]);
 }

 //NullPointerException
 @Test
 public void test6(){
 int[] arr = null;
 System.out.println(arr[1]);
 }

编译时异常

/* ******************以下是编译时异常****************** */
 @Test
 public void test7(){
 File file = new File("a.txt");
 //java.io.FileNotFoundException
 FileInputStream fis = new FileInputStream(file);
 //java.io.IOException
 int date = fis.read();
 while (date != -1){
  System.out.println((char)date);
  date = fis.read();
 }

 fis.close();
 }

ps:对于编译时异常,我们需要异常处理

三.异常处理:抓抛模型

1.抓抛解释

过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象, 并将此对象抛出;一旦抛出对象以后,其后的代码就不再执行。

关于异常对象的产生:

① 系统自动生成的异常对象

② 手动的生成一个异常对象,并抛出(throw)

过程二:“抓”:可以理解为异常的处理方式:① try-catch-finally ② throws

2.try-catch-finally的使用

try{
//可能出现异常的代码

}catch(异常类型1 变量名1){
//处理异常的方式1
}catch(异常类型2 变量名2){
//处理异常的方式2
}catch(异常类型3 变量名3){
//处理异常的方式3
}
…
finally{
//一定会执行的代码
}

说明:

  1. finally是可选的。
  2. 使用try将可能会出现异常的代码段包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配
  3. 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的
    try-catch结构(在没有写finally的情况)。继续执行其后的代码
  4. catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
    catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
  5. 常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
  6. 在try结构中声明的变量,再出了try结构以后,就不能再被调用
  7. try-catch-finally结构可以嵌套
  8. finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。
  9. 像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。

示例一:

@Test
public void test1(){
 String str = "abcd";
 int num = 1314;
 try {
 num = Integer.parseInt(str);

 System.out.println("进入try代码块!");
 }catch (NumberFormatException e){
 System.out.println("出现数值转换异常了!");
 System.out.println(e.getMessage());
 e.printStackTrace();
 System.out.println("该catch语句块将要执行完了!");
 } catch (NullPointerException e){
 System.out.println("出现空指针异常!");
 } catch (Exception e){
 System.out.println("出现异常了");
 }finally {
 System.out.println("执行finally语句了!");
 }
 System.out.println(num);
}

输出结果:

示例二:

 @Test
 public void test2(){
  File file = new File("a.txt");
  FileInputStream fis = null;
  try {
   fis = new FileInputStream(file);
   int date = fis.read();
   while(date != -1){
    System.out.println((char)date);
    date = fis.read();
   }

  } catch (FileNotFoundException e) {
   e.printStackTrace();
  }catch (IOException e){
   e.printStackTrace();
  }finally {
   System.out.println("执行finally语句了!");
   try {
    fis.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

输出结果:

总结:

  • 使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
  • 开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。

3.throws + 异常类型的使用

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

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

子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(子类重写的方法也可以不抛出异常)

public class SuperClass {
 public void method() throws IOException {

 }
}

class SubClass extends SuperClass{
 //报错,子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
// public void method() throws Exception{
//
// }

 public void method() throws FileNotFoundException{

 }
}

开发中如何选择使用try-catch-finally 还是使用throws? 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果

子类重写的方法中有异常,必须使用try-catch-finally方式处理。执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws

的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。

代码示例:

public class ErrorThrows {
 public static void method1() throws IOException {
  File file = new File("a.txt");
  FileInputStream fileInputStream = new FileInputStream(file);

  int data = fileInputStream.read();
  while(data != -1){
   System.out.println((char)data);
   data = fileInputStream.read();
  }
  fileInputStream.close();
 }

 public static void method2() throws IOException {
  method1();
 }

 public static void method3() throws IOException {
  method1();
 }

 public static void main(String[] args) {
  try {
   method3();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
}

4.手动抛出一个异常类对象(throw关键字使用)

代码示例:

public class ReturnException {
 static void method1(){
  try{
   System.out.println("进入方法1");
   throw new RuntimeException("手动抛出异常");
  }catch (Exception e){
   e.printStackTrace();
   System.out.println(e.getMessage());
  } finally {
   System.out.println("执行finally语句了!");
  }
 }

 public static void main(String[] args) {
  method1();
 }
}

输出结果:

四.自定义异常类

自定义异常类,有如下三步骤:

  • 继承于现有的异常结构:RuntimeException 、Exception
  • 提供全局常量:serialVersionUID
  • 提供重载的构造器

自定义异常类:

public class MyExceptionClass extends Exception{

 static final long serialVersionUID = -5641210210148784L;

 public MyExceptionClass() {
 }

 public MyExceptionClass(String message) {
  super(message);
 }
}

手动抛出上述自定义的异常类对象:

public class MyExceptionTest {

 static void method1() throws MyExceptionClass {
  Scanner scanner = new Scanner(System.in);

  System.out.println("请输入大于0的数据:");
  double next = scanner.nextDouble();
  if(next >0){
   System.out.println("您输入的数据为:"+next);
  }else {
   throw new MyExceptionClass("您输入的数据不满足要求!");
  }
 }

 public static void main(String[] args) {
  try {
   method1();
  } catch (MyExceptionClass myExceptionClass) {
   myExceptionClass.printStackTrace();
  }
 }
}

运行结果:

到此这篇关于非常全面的Java异常处理的文章就介绍到这了,更多相关Java异常处理干货内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2020-11-21

java中的connection reset 异常处理分析

在Java中常看见的几个connection rest exception, Broken pipe, Connection reset,Connection reset by peer Socked reset case Linux中会有2个常见的sock reset 情况下的错误代码 ECONNRESET 该错误被描述为"connection reset by peer",即"对方复位连接",这种情况一般发生在服务进程较客户进程提前终止.当服务进程终止时会向客户

java进行error捕获和处理示例(java异常捕获)

下面给个小例子,来验证一下error的捕获. 复制代码 代码如下: public class TestCatchError extends Error{ private static final long serialVersionUID = -351488225420878020L; public TestCatchError(){        super();    } public TestCatchError(String msg){        super(msg);    } p

java基于spring注解AOP的异常处理的方法

一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...finally对异常进行处理,但是我们真的能在写程序的时候处理掉所有可能发生的异常吗? 以及发生异常的时候执行什么逻辑,返回什么提示信息,跳转到什么页面,这些都是要考虑到的. 二.基于@ControllerAdvice(加强的控制器)的异常处理 @ControllerAdvice注解内部使用@Except

深入探讨JAVA中的异常与错误处理

异常与错误: 异常: 在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通知你的一种方式,通过这种方式,VM让你知道,你(开发人员)已经犯了个错误,现在有一个机会来修改它.Java中使用异常类来表示异常,不同的异常类代表了不同的异常.但是在Java中所有的异常都有一个基类,叫做Exception. 错误: 它指的是一个合理的应用程序不能截获的严重的问题.大多数都是反常的情况.错误是VM的一个故障(虽然它可以是任何系统级的服务).

Java程序常见异常及处理汇总

一.JDK中常见的异常情况 1.常见异常总结图 2.java中异常分类 Throwable类有两个直接子类: (1)Exception:出现的问题是可以被捕获的 (2)Error:系统错误,通常由JVM处理 3.被捕获的异常分类 (1)Check异常: 派生自Exception的异常类,必须被捕获或再次声明抛出 (2)Runtime异常:派生自RuntimeException的异常类.使用throw语句可以随时抛出这种异常对象 throw new ArithmeticException(-);

浅谈java异常处理之空指针异常

听老师说,在以后的学习中大部分的异常都是空指针异常.所以抽点打游戏的时间来查询一下什么是空指针异常 一:空指针异常产生的主要原因如下: (1)当一个对象不存在时又调用其方法会产生异常obj.method() // obj对象不存在 (2)当访问或修改一个对象不存在的字段时会产生异常obj.method() // method方法不存在 (3)字符串变量未初始化: (4)接口类型的对象没有用具体的类初始化,比如: List lt:会报错 List lt = new ArrayList():则不会报

java异常处理机制示例(java抛出异常、捕获、断言)

这是一个介绍基本异常处理的小例子,包括抛出,捕获,断言,日志. Java异常处理通过5个关键字try.catch.throw.throws.finally进行管理.基本过程是用try语句块包住要监视的语句,如果在try语句块内出现异常,则异常会被抛出,你的代码在catch语句块中可以捕获到这个异常并做处理;还有以部分系统生成的异常在Java运行时自动抛出.你也可以通过throws关键字在方法上声明该方法要抛出异常,然后在方法内部通过throw抛出异常对象. 复制代码 代码如下: package

详解Java异常处理中throw与throws关键字的用法区别

抛出异常 抛出异常有三种形式,一是throw,一个throws,还有一种系统自动抛异常.下面它们之间的异同. 系统自动抛异常 当程序语句出现一些逻辑错误.主义错误或类型转换错误时,系统会自动抛出异常.如: public static void main(String[] args) { int a = 5, b =0; System.out.println(5/b); //function(); } 系统会自动抛出ArithmeticException异常: Exception in threa

Java异常处理之try...catch...语句的使用进阶

try就像一个网,把try{}里面的代码所抛出的异常都网住,然后把异常交给catch{}里面的代码去处理.最后执行finally之中的代码.无论try中代码有没有异常,也无论catch是否将异常捕获到,finally中的代码都一定会被执行. 虽然 Java 执行时期系统所提供的预设处理器对除错很有用,你通常想要自己处理例外.这样做有两个优点:第一,它让你修正错误.第二,它可以避免程式自动终止.每当错误发生时,如果你的程式就停止而且列印出堆叠追踪,大多数的使用者都会感到很困惑.很幸运,你很容易就能

Java中异常处理之try和catch代码块的使用

Java try和catch的使用 尽管由Java运行时系统提供的默认异常处理程序对于调试是很有用的,但通常你希望自己处理异常.这样做有两个好处.第一,它允许你修正错误.第二,它防止程序自动终止.大多数用户对于在程序终止运行和在无论何时错误发生都会打印堆栈轨迹感到很烦恼(至少可以这么说).幸运的是,这很容易避免. 为防止和处理一个运行时错误,只需要把你所要监控的代码放进一个try块就可以了.紧跟着try块的,包括一个说明你希望捕获的错误类型的catch子句.完成这个任务很简单,下面的程序包含一个

Java中自定义异常详解及实例代码

Java中自定义异常详解及实例代码 下面做了归纳总结,欢迎批评指正 自定义异常 class ChushulingException extends Exception { public ChushulingException(String msg) { super(msg); } } class ChushufuException extends Exception { public ChushufuException(String msg) { super(msg); } } 自定义异常 En

Java中的静态内部类详解及代码示例

1. 什么是静态内部类 在Java中有静态代码块.静态变量.静态方法,当然也有静态类,但Java中的静态类只能是Java的内部类,也称为静态嵌套类.静态内部类的定义如下: public class OuterClass { static class StaticInnerClass { ... } } 在介绍静态内部类之前,首先要弄清楚静态内部类与Java其它内部类的区别. 2. 内部类 什么是内部类?将一个类的定义放在另一个类的内部,就是内部类.Java的内部类主要分为成员内部类.局部内部类.

JAVA中Integer值的范围实例代码

废话不多说了,直接给大家贴代码,具体代码如下所示: package com.test; public class Test { public static void main(String []args) { Integer a = 100;//此处若使用new,则==值必为false Integer b = 100; System.out.println(a==b);//true Integer c = 150; Integer d = 150; System.out.println(c==d

Java中Volatile关键字详解及代码示例

一.基本概念 先补充一下概念:Java内存模型中的可见性.原子性和有序性. 可见性: 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情.为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的.也就是一个线程修改的结果.另一个线程马上就能看到.比如:用volatile修饰的变量,就会具有可见性.volatile修饰的

在java中使用dom4j解析xml(示例代码)

虽然Java中已经有了Dom和Sax这两种标准解析方式 但其操作起来并不轻松,对于我这么一个初学者来说,其中部分代码是活生生的恶心 为此,伟大的第三方开发组开发出了Jdom和Dom4j等工具 鉴于目前的趋势,我们这里来讲讲Dom4j的基本用法,不涉及递归等复杂操作 Dom4j的用法很多,官网上的示例有那么点儿晦涩,这里就不写了 首先我们需要出创建一个xml文档,然后才能对其解析 xml文档: 复制代码 代码如下: <?xml version="1.0" encoding=&quo

详解Java中接口的定义与实例代码

Java中接口的定义详解 1.定义接口 使用interface来定义一个接口.接口定义同类的定义类似,也是分为接口的声明和接口体,其中接口体由常量定义和方法定义两部分组成.定义接口的基本格式如下: [修饰符] interface 接口名 [extends 父接口名列表]{ [public] [static] [final] 常量; [public] [abstract] 方法; } 修饰符:可选,用于指定接口的访问权限,可选值为public.如果省略则使用默认的访问权限. 接口名:必选参数,用于

Java中的按值传递和按引用传递的代码详解

先使用int实验: public class TTEST { private static List<UserEntity> mList = new LinkedList<UserEntity>(); public static void main(String[] args) { int a = 0; changeA(a); System.out.println("a = "+a); } public static void changeA(int a){ a

java中通用的线程池实例代码

复制代码 代码如下: package com.smart.frame.task.autoTask; import java.util.Collection;import java.util.Vector; /** * 任务分发器 */public class TaskManage extends Thread{    protected Vector<Runnable> tasks = new Vector<Runnable>();    protected boolean run

java中UDP简单聊天程序实例代码

学过计算机网络通信的都知道,计算机之间传送数据由两种,即TCP通信和UDP通信.TCP是可靠的面向连接的通信协议,二UDP是不可靠的面向无连接的通信协议. java中有基于TCP的网络套接字通信,也有基于UDP的用户数据报通信,UDP的信息传输速度快,但不可靠! 基于UDP通信的基本模式: (1)将数据打包,称为数据包(好比将信件装入信封一样),然后将数据包发往目的地. (2)接受别人发来的数据包(好比接收信封一样),然后查看数据包中的内容. 客户机 复制代码 代码如下: package com