Java学习笔记---异常

(1)异常的捕获和处理

(1.1)基本介绍

(1)为什么需要异常处理

开一段平稳的路,出问题的概率比较小,就可以不用检查。但是出现了一段山路,车子出问题的风险就比较大,我们不能等出了问题再去解决,而是应该未雨绸缪,提前检查容易出问题的地点

(2)有哪些异常

异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出 java.lang.ArithmeticException 的异常。

异常发生的原因有很多,通常包含以下几大类:
1-用户输入了非法数据。
2-要打开的文件不存在。
3-网络通信时连接中断,或者JVM内存溢出。

要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:
(1)检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
(2)运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
(3)错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

异常是导致程序中断运行的一种指令流,除了Java中已经提供的各种异常类外,用户可以根据定义自己的异常类。
在这里插入图片描述

(3)异常之间的区别

(1)Error是不可查的,是程序不应该出现的,这些故障往往发生在虚拟机自身或者虚拟机试图执行应用时
(2)Exception是程序自身可以处理的异常

(1.2)Java内置异常类

【1】列出了 Java 的非检查性异常。

(1)ArithmeticException 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。
(2)ArrayIndexOutOfBoundsException 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。
(3)ArrayStoreException 试图将错误类型的对象存储到一个对象数组时抛出的异常。
(4)ClassCastException 当试图将对象强制转换为不是实例的子类时,抛出该异常。
(5)IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。
(6)IllegalMonitorStateException 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。
(7)IllegalStateException 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。
(8)IllegalThreadStateException 线程没有处于请求操作所要求的适当状态时抛出的异常。
(9)IndexOutOfBoundsException 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
(10)NegativeArraySizeException 如果应用程序试图创建大小为负的数组,则抛出该异常。
(11)NullPointerException 当应用程序试图在需要对象的地方使用 null 时,抛出该异常
(12)NumberFormatException 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
(13)SecurityException 由安全管理器抛出的异常,指示存在安全侵犯。
(14)StringIndexOutOfBoundsException 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。
(15)UnsupportedOperationException 当不支持请求的操作时,抛出该异常。

【2】列出了 Java 定义在 java.lang 包中的检查性异常类。

(1)ClassNotFoundException 应用程序试图加载类时,找不到相应的类,抛出该异常。
(2)CloneNotSupportedException 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。
(3)IllegalAccessException 拒绝访问一个类的时候,抛出该异常。
(4)InstantiationException 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。
(5)InterruptedException 一个线程被另一个线程中断,抛出该异常。
(6)NoSuchFieldException 请求的变量不存在
(7)NoSuchMethodException 请求的方法不存在

(1.2)异常方法

Throwable 类的主要方法:
1-public String getMessage():返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。
2-public Throwable getCause():返回一个 Throwable 对象代表异常原因。
3-public String toString():返回此 Throwable 的简短描述。
4-public void printStackTrace():将此 Throwable 及其回溯打印到标准错误流。
5-public StackTraceElement [] getStackTrace():返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。
6-public Throwable fillInStackTrace():用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。

(1.2)为什么需要异常处理

如果没有异常处理,要避免异常就要使用大量的判断语句来捕捉程序里可能发生的错误,导致运行效率的降低。
java的异常处理机制易于使用、可以自己定义异常类、处理抛出的异常时又不会降低程序运行的速度。

(1.3)使用异常处理

(1)关键字
try:{有可能出现异常的语句}
catch:(异常类,异常对象),{异常的具体处理语句}
finally:{一定会运行到的程序代码}—finally作为异常的同一出口,尽可能不要出现throw或return这样的语句

(2)异常处理过程
1-一旦产生异常,则首先会产生一个异常类的实例化对象
2-在try语句中对此异常对象进行捕捉
3-产生的异常对象和catch语句中的各个异常类型进行匹配,如果匹配成功,则执行catch语句中的代码

(3)异常信息的输出方法
1-System.out.println(“数组越界异常:”+e);
2-e.printStackTrace(); 使用这种方式打印的异常信息是最完整的

(1.3.1)对异常进行捕捉(try、catch、finally)
public class Test02 {
	public static void main(String[] args) {
		System.out.println("**********计算开始*********");
		int i=0;
		int j=10;
		try {
			int temp=j/i;
			System.out.println("两个数字相除结果为:"+temp);
			System.out.println("______________________");
		} catch (ArithmeticException e) {   //捕捉算术异常
			// TODO: handle exception
			System.out.println("出现了异常:"+e);  //当出现异常,就执行这个语句
		}finally {  //异常的统一出口
			System.out.println("不管是否出现异常,都执行这行代码");
		}
		System.out.println("**********计算结束*********");
	}
}
(1.3.2)抛出多个异常
public class Test03 {
	public static void main(String[] args) {
		System.out.println("+++++++++++计算开始+++++++++++++");
		int i=0;
		int j=0;
		try {
//			接收参数
			String str1=args[0];
			String str2=args[1];
//			将参数由字符串变为整型
			i=Integer.parseInt(str1);
			j=Integer.parseInt(str2);
			int temp=i/j;
			System.out.println("两个数字相除结果为:"+temp);
			System.out.println("______________________");
		} catch (ArithmeticException e) {
			// TODO: handle exception
			System.out.println("算术异常:"+e);  //当出现异常,就执行这个语句
		} catch (NumberFormatException e) {
			// TODO: handle exception
			System.out.println("数字转换异常:"+e);  //当出现异常,就执行这个语句
		} catch (ArrayIndexOutOfBoundsException e) {
			// TODO: handle exception
			System.out.println("数组越界异常:"+e);  //当出现异常,就执行这个语句
		} 
//		必须把范围小的放前面,范围大的放后面,其他异常的范围最大
		catch (Exception e) {
			System.out.println("其他异常:"+e);  //捕捉其他异常,全部异常都可以处理
			// TODO: handle exception
		}
		
		System.out.println("**********计算结束*********");
	}

}

(1.4)异常类的继承结构和分类

(1)异常结构中,有两个最常用的类,两个类都是Throwable的子类

  • Exception:表示的是程序中出现的问题,可以直接使用try…catch处理,是最大的捕捉范围。多个异常要分别进行捕获,不要直接使用Exception捕获全部异常。
  • Error:一般值得是JVM错误,程序中无法处理
(1.4.1)异常分类

(1)可查异常 CheckedException( 可查异常即必须进行处理的异常)
要么try catch住,要么往外抛,谁调用,谁处理,比如 FileNotFoundException。如果不处理,编译器,就不让你通过
(2)运行时异常 RuntimeException( 不是必须进行try catch的异常,可以不处理,交给虚拟机;如果非要捕捉也可以 )
1-常见异常:
除数不能为0异常:ArithmeticException
下标越界异常:ArrayIndexOutOfBoundsException
空指针异常:NullPointerException
2-特点:
在编写代码的时候,依然可以使用try catch throws进行处理,与可查异常不同之处在于,即便不进行try catch,也不会有编译错误
Java之所以会设计运行时异常的原因之一,是因为下标越界,空指针这些运行时异常太过于普遍,如果都需要进行捕捉,代码的可读性就会变得很糟糕。
(3)错误 Error( 指的是系统级别的异常, 通常是内存用光了)
1-在默认设置下,一般java程序启动的时候,最大可以使用16m的内存
2-如例不停的给StringBuffer追加字符,很快就把内存使用光了。抛出OutOfMemoryError
3-与运行时异常一样,错误也是不要求强制捕捉的

(1.5)throws与throw关键字

(1)throws关键字
在定义一个方法时可以使用throws关键字声明,表示这个方法不处理异常,而是交给方法的调用处进行处理,谁调用这个方法谁再用try…catch进行处理。

public class Test04 {
	public static void main(String[] args) {
		Math m=new Math();
		try {
			System.out.println("除法操作:"+m.div(10, 2));
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();  //打印异常
		}
	}

}

//在方法里面定义throws
class Math{
	public int div(int i,int j) throws Exception{  //方法可以不处理异常
		int temp=i/j;
		return temp;
	}
}

不要在主方法里使用throws关键字,主方法是一切的起点,所以此时主方法再向上抛异常,则只能把异常抛给JVM进行处理。

(2)throw关键字
使用throw关键字人为第抛出一个异常,抛出时直接抛出异常类的实例化对象。

public class ThrowDemo01 {
	public static void main(String[] args) {
		try {
			throw new Exception("自己抛出异常!");
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println(e);
		}
	}
}

(3)throws和throw的区别
throws是加在方法上,自动向调用处抛异常,表示不处理
throw是加在try语句中,表示这个异常被手动的抛出,表示不处理

(1.6)自定义异常

记住下面的几点:
1-所有异常都必须是 Throwable 的子类。
2-如果希望写一个检查性异常类,则需要继承 Exception 类。
3-如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。

class MyException extends Exception{
	public MyException(String msg){
		super(msg);
	}
}

自定义异常案例


// 文件名InsufficientFundsException.java
import java.io.*;
 
//自定义异常类,继承Exception类
public class InsufficientFundsException extends Exception
{
  //此处的amount用来储存当出现异常(取出钱多于余额时)所缺乏的钱
  private double amount;
  public InsufficientFundsException(double amount)
  {
    this.amount = amount;
  } 
  public double getAmount()
  {
    return amount;
  }
}

//此类模拟银行账户
public class CheckingAccount
{
  //balance为余额,number为卡号
   private double balance;
   private int number;
   public CheckingAccount(int number)
   {
      this.number = number;
   }
  //方法:存钱
   public void deposit(double amount)
   {
      balance += amount;
   }
  //方法:取钱
   public void withdraw(double amount) throws
                              InsufficientFundsException
   {
      if(amount <= balance)
      {
         balance -= amount;
      }
      else
      {
         double needs = amount - balance;
         throw new InsufficientFundsException(needs);
      }
   }
  //方法:返回余额
   public double getBalance()
   {
      return balance;
   }
  //方法:返回卡号
   public int getNumber()
   {
      return number;
   }
}

public class BankDemo
{
   public static void main(String [] args)
   {
      CheckingAccount c = new CheckingAccount(101);
      System.out.println("Depositing $500...");
      c.deposit(500.00);
      try
      {
         System.out.println("\nWithdrawing $100...");
         c.withdraw(100.00);
         System.out.println("\nWithdrawing $600...");
         c.withdraw(600.00);
      }catch(InsufficientFundsException e)
      {
         System.out.println("Sorry, but you are short $"
                                  + e.getAmount());
         e.printStackTrace();
      }
    }
}

Depositing $500…
Withdrawing $100…
Withdrawing $600…
Sorry, but you are short $200.0
InsufficientFundsException
at CheckingAccount.withdraw(CheckingAccount.java:25)
at BankDemo.main(BankDemo.java:13)

(1.7)断言

(2)常见异常分类

(1)下标越界异常:ArrayIndexOutOfBoundsException(运行时异常,可以不处理,让虚拟机接管)

int Arry_a[] = new int[10];
System.out.println(Arry_a[10]);

(2)除数不能为0异常:ArithmeticException(运行时异常)

(3)空指针异常:NullPointerException(运行时异常)

(3)常见问题

(1)运行时异常与非运行时异常的区别?
Throwable 是所有 Java 程序中错误处理的父类 ,有两种资类: Error 和 Exception 。 Error :表示由 JVM 所侦测到的无法预期的错误,由于这是属于 JVM 层次的严重错误 ,导致 JVM 无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。 Exception :表示可恢复的例外,这是可捕捉到的。 Java 提供了两类主要的异常 :runtime exception 和 checked exception 。 checked 异常也就是我们经常遇到的 IO 异常,以及 SQL 异常都是这种异常。 对于这种异常, JAVA 编译器强制要求我们必需对出现的这些异常进行 catch 。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆 catch 块去处理可能的异常。 但是另外一种异常: runtime exception ,也称运行时异常,我们可以不处理当出现这样的异常时,总是由虚拟机 接管。比如:我们从来没有人去处理过 NullPointerException 异常,它就是运行时异常,并且这种异常还是最常见的异常之一。 出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果没有处理块,到最上层,如果是多线程就由 Thread.run() 抛出 ,如果是单线程就被 main() 抛出 。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。运行时异常是 Exception 的子类,也有一般异常的特点,是可以被 Catch 块处理的。只不过往往我们不对他处理罢了。也就是说,你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。 如果不想终止,则必须扑捉所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。 在这个场景这样处理可能是一个比较好的应用,但并不代表在所有的场景你都应该如此。如果在其它场景,遇到了一些错误,如果退出程序比较好,这时你就可以不太理会运行时异常 ,或者是通过对异常的处理显式的控制程序退出。

(2)以下代码运行结果是:try catch finally
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值