Java 异常处理

目录

 

Java 异常处理

异常概述

异常处理机制

Exception 类的层次

Java常见异常

Java 内置异常类

异常方法

异常的捕获和处理

自定义异常

通用异常


Java 异常处理

异常概述

   在程序中错误可能产生于程序员没有预料到的各种情况,或者超出了程序员可控范围的环境因素。

   在Java中在程序运行时可能出现的错误叫做异常。

   异常是一个在程序执行期间发生的事,它中断了正在执行的程序的正常指令流。

   异常机制已经成为判断一门编程语言是否成熟的标准。

   其实异常就是 Java 通过面向对象的思想将程序中的问题封装成了对象,用异常类对其进行描述。
 
    ① 不同的问题用 不同的类进行具体的描述。
 
    ② 问题很多,意味着描述的类也很多,将其共性进行向上抽取就形成了异常体系
 

   错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

package yichang;
/** 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。
比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;
如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛java.lang.ArithmeticException 的异常。
*/ 
public class D1 {
	public static void main(String[] args) {
		System.out.println(10);//会执行
		double a = 10/0;
		System.out.println(a);//不会执行
		System.out.println(100);//不会执行
	}
   

}
/**执行结果
10
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at yichang.D1.main(D1.java:6)
*/

程序员真理程序会出错!!!

    异常发生的原因通常有:
  • 用户输入了非法数据。
  • 要打开的文件不存在。
  • 网络通信时连接中断,或者JVM内存溢出。

    这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。

  • 检查性异常(Checked):最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的

        例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。

            Java认为Checked异常都是可以在编译阶段被处理的异常,所以强制程序处理所有的Checked异常

            Checked异常体现了java设计哲学:没有完善处理的代码根本不会被执行,体现了java的严谨性

        Checked异常的处理方式:

            ①:当方法明确知道如何处理异常,程序应该使用try...catch块来捕获该异常,然后在对应的catch块中修补该异常。

            ②:当方法不知道如何处理异常,应该在定义该方法时声明抛出该异常。

  • 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。

            Runtime异常无须显式声明抛出,如果程序需要捕捉Runtime异常,也可以使用try...catch块来捕获Runtime异常。

            问题是:大部分的方法总是不能明确知道如何处理异常,这就只能声明抛出异常了。

异常处理机制

    设计良好的程序应该在异常发生时提供处理这些错误,使得程序不会因为异常的发生而阻断或者产生不可预见的结果
 
 抛出异常   Java 程序的执行过程中出现异常事件,可以生成一个异常类对象,该异常对象封装了异常事件的信息并 被提交给 Java 运行时系统,这个过程称为抛出异常 throw 。
 
  捕获异常    当Java 运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这个过程 称为捕获异常 。
 
 关键字      Java 异常处理的关键字有 throws throw try catch finally 5 个关键字
 
Java 语言提供了异常处理机制,为方法的异常终止和出错处理提供了清楚的接口
 
  ① 用来在发生运行异常时告诉程序如何控制自身的运行,以防止错误的进一步恶化
 
  ② 每个方法必须对他可能抛出的异常进行预先声明,在定义方法时,必须声明这个方法可能会抛出哪一种或几种 异常
 

Exception 类的层次

  • 所有的异常类是从 java.lang.Exception 类继承的子类。
  • Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error 。
  • Java 程序通常不捕获错误。它们在Java程序处理的范畴之外。
  • Error 用来指示运行时环境发生的错误。例如,JVM 内存溢出。一般地,程序不会从错误中恢复。

  • 异常类有两个主要的子类:IOException 类和 RuntimeException 类。

 
JavaSE 中定义了很多异常类,这些类可以对应各种各样可能出现的异常事件。
 
Throwable 类是 Java 异常类型的顶层父类,一个对象只有是 Throwable 类的(直接或者间接)实例,他才是一个异常对象,才能被异常处理机制识别
 

Java常见异常

所有异常对象的父类为 Throwable---Object
 
Java异常可以分为3大类
 
1 Error 及其子类:错误,一般指的是虚拟机的错误,是由 Java 虚拟机生成并抛出,程序不能进行处理所以也不加
处理,例如 OutOfMemoryError 内存溢出、调用栈溢出 StackOverFlowError
package yichang;

public class D2 {
	public static void main(String[] args) {
		D2.pp();//无限循环调用了 
	}
	public static void pp() {
		System.out.println("this is pp....");
		pp();
	}
}
/**
运行结果
。。。
。。。
this is pp....
this is pp....
this is pp....
Exception in thread "main" java.lang.StackOverflowError
。。。
。。。
*/
2 RuntimeException 及其子类:运行时异常 ( 非受检型异常 )
 
是由于编程 bug 所导致,希望越早发现越好,所以 不进行处理,直接中断报错即可。
 
编程人员针对报错信息修改程序 bug 来解决问题。
 
举例常见的五种异常:
 
①常见的第一种运行时异常: ArithmeticException 算术异常,就是执行数学计算时产生的非正常情况,如除以 0
package yichang;

public class D1 {
	public static void main(String[] args) {
	//	double a = 10 / 0;    //修改bug注释掉
//这里明显是一个编程的bug,因为除法计算要求分母非0。修正bug,这里进行分母为0的处理

		int k = 0;
		if (k != 0)
			System.out.println(10 / k);
		else
			System.out.println("除数为0,不能执行除法计算");
		System.out.println("end.....");
	}
}
/**运行结果:
除数为0,不能执行除法计算
end.....
*/
②常见的 第二种运行时异常: NullPointerException 空指针异常(试图访问 null 对象的引用)
package yichang;

public class D3 {
public static void main(String[] args) {
	D3 a = new D3();
	a=null;
	System.out.println(a); // println 方法 String s = String.valueOf(x); 输出String值
	System.out.println(a.toString()); //D3继承了object的toString()方法,输出对象的地址
}
}
/**
输出结果
null
Exception in thread "main" java.lang.NullPointerException
	at yichang.D3.main(D3.java:8)

这里出错的原因是调用对象的方法之前没有进行非空判断,所以NullPointerException
bug处理方法
if (a != null) 
		System.out.println(a.hashCode()); 
	else
		System.out.println("obj没有具体对象");
*/
③常见的 第三种运行时异常: IndexOutOfBoundsException 下标出界
package yichang;

public class D4 {
public static void main(String[] args) {
	int[] arr=new int[3]; //异常的原因是访问数组的下标超出允许的范围[0,arr.length]
	System.out.println(arr[3]); //ArrayIndexOutOfBoundsException 
	//异常的原因是通过下标访问字符串中字符时,超出了下标允许的范围[0,str.length()]
	String str="abcd";
	System.out.println(str.charAt(4));//StringIndexOutOfBoundsException
}
}
/**运行結果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
	at yichang.D4.main(D4.java:6)
解决方法:通过下标访问时应该判定下标的取值是否合法
int[] arr = new int[] { 1, 2, 3, 4 };
int index = 0; 
if (index >= 0 && index < arr.length) 
System.out.println(arr[index]);// 避免ArrayIndexOutOfBoundsException
String str = "asdfasdf";
if (index >= 0 && index < str.length())
System.out.println(str.charAt(index));// 避免StringIndexOutOfBoundsException
*/

常见的 第四种运行时异常:ClassCastException试图把一个对象转换成非法类型

package yichang;

public class D5 extends DA {
	public static void main(String[] args) {
		Object a = new D5();
		D5 c = new D5();
		DA cc = new DA();
		DA d = (DA) c; // 强转a或c都可以运行
		// DB b = (DB)a; //a用c不能通过编译 ,DB类和D5类没关系,不能强转 用a编译可以通过视为向下转型,运行不行实际上是D5类没关系
		D5 e = (D5) cc;// 可以通过编译,但是发生向下转型异常
	}
}

class DA {
	public DA() {
		System.out.println("调用DA方法!");
	}

}

class DB {

}

/**
运行结果:
调用DA方法!
调用DA方法!
调用DA方法!
Exception in thread "main" java.lang.ClassCastException: yichang.DA cannot be cast to yichang.D5
	at yichang.D5.main(D5.java:10)

解决方案:进行类型强制转换之前,应该对变量类型进行判断,如果合法才进行类型的转换
D5 e = (D5) cc;替换为:
if(cc!=null && cc instanceof D5){ 
D5 e = (D5)cc; 
}
else
   System.out.println("cc不是D5类型");
*/

⑤常见的第五种运行时异常:NumberFormatException数据格式异常,一般出现在数据类型转换中

package yichang;

public class D6 {// NumberFormatException数据格式异常,一般出现在数据类型转换中
	public static void main(String[] args) {
		String a = "1.23";
		Double c = Double.parseDouble(a);//可以运行
		System.out.println(c);
		Integer b = Integer.parseInt(a);// 可以通过编译,但不能运行
		System.out.println(b);
	}
}
/**
运行结果:
1.23
Exception in thread "main" java.lang.NumberFormatException: For input string: "1.23"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:580)
	at java.lang.Integer.parseInt(Integer.java:615)
	at yichang.D6.main(D6.java:8)
*/

 这里进行数据的合法性验证后再进行数据类型转换比较繁琐,所以最终的解决方案是使用try/catch语法结果,针对出现问题后进行处理

package yichang;

public class D6 {// NumberFormatException数据格式异常,一般出现在数据类型转换中
	public static void main(String[] args) {
		String a = "1.23";
		Double c = Double.parseDouble(a);
		System.out.println(c);
		Integer kk = 0;
		try {
			kk = Integer.parseInt(a); // 如果没有问题则进行数据类型转换
		} catch (NumberFormatException e) {
			kk = 100;// 如果数据不合法,则使用这个默认值
		}
		System.out.println(kk);
	}

}
/**
输出结果:
1.23
100
*/
3 Exception 及其子类中除了 RuntimeException 及其子类之外的其它异常:
 
     受检型异常 ( 非运行时异常 ), 这类异常属于明知道可能出现,但是没有办法杜绝的异常。所以必须进行编码异常处理 !
 
     这类异常一般采用 try/catch 或者 throws 声明抛出的方式进行异 常处理,当程序出现了非正常情况,尽量保证程序正常结果,而不是立即中断
 
     运行时异常:这种异常不需要进行处理,发现的越早越好,改BUG 。
 

Java 内置异常类

Java 根据各个类库也定义了一些其他的异常,下面的表中列出了 Java 的非检查性异常。

下面的表中列出了 Java 定义在 java.lang 包中的检查性异常类。

 

异常方法

下面的列表是 Throwable 类的主要方法:

异常的捕获和处理

try {
      try 代码段中包含可能产生异常的代码,有人称为陷阱代码,在执行过程中如果出现了异常,则异常之后的
      java 语句不会执行。转而执行 catch 部分的代码
} catch ( SomeException e ){
      可以写多个catch
      try 后可以跟一个多个 catch 代码段,针对不同异常执行不同的处理逻辑。当异常发生时,程序会中止当前的
      流程,根据获取异常的类型去执行响应的代码段。注意异常类型判定时是从上向下逐个判断的。
} finally {
      finally 代码是无论是否发生异常都会执行的代码
}

注意:

  • try块中的局部变量和catch块中的局部变量(包括异常变量),以及finally中的局部变量,他们之间不可共享使用。
  • Java采用的是终结式异常处理机制,java中异常处理的任务就是将执行控制流从异常发生的地方转移到能够处 理这种异常的地方去。也就是说:当一个函数的某条语句发生异常时,这条语句的后面的语句不会再执行。它失去了焦点,执行流跳转到最近的匹配的异常处理catch代码块去执行,异常被处理完后,执行流会接着处理了这个异常的catch代码块后面接着执行。
  • try{}后面必须跟一个finally或者catch,其中有个特殊写法可以省略后面的finallycatch
package yichang;

public class D7 {
	public static void main(String[] args) {
		Integer kk = null;
		try {
			String str = "123.456"; 
			kk = Integer.parseInt(str); // 由于str参数数据不合法,不是整数,所以这里异常NumberFormatException
			System.out.println("数据转换结束");// 上句出现异常,这里就不会执行
		} catch (Exception e) {// 出现异常后进行类型判断,如果是这种异常则执行这里的代码段,可以有多个捕捉异 常
			System.out.println("出现了错误:" + e.getMessage()); // e.getMessage():String用于获取异常的 提示信息
			e.printStackTrace(); // 在控制台(标准错误流System.err)上输出异常调用栈。底层问题输出顺序未必就在System.out.println("转换结果为:" + kk);前面,随机的。
		}
		System.out.println("转换结果为:" + kk);
	}
}

输出结果:

出现了错误:For input string: "123.456"
java.lang.NumberFormatException: For input string: "123.456"
转换结果为:null
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at yichang.D7.main(D7.java:8)

     try-- 用于监听。将要被监听的代码 ( 可能抛出异常的代码 ) 放在 try 语句块之内。 try语句块内发生异常时,异常就被抛出。如果没有异常产生,所有的 catch 代码段都能略过不执行
     catch-- 用于捕获异常 catch 用来捕获 try语句块中发生的异常。catch 可以消费掉异常,这个异常不会再提交运行时环境处理 。
     finally--finally语句块总是会被执行。
         它主 要用于回收在 try 块里打开的资源 ( 如数据库连接、网络连接和磁盘文件 )
         只有 finally 块,执行完成之后,才会执行 try 或者 catch 块中的 return 或者 throw 语句,如果 finally 中使用了 return 或者 throw 等终止方法的语句,则就不会跳 回执行,直接停止。
  • catch 不能独立于 try 存在。
  • 在 try/catch 后面添加 finally 块并非强制性要求的。
  • try 代码后不能既没 catch 块也没 finally 块。
  • try, catch, finally 块之间不能添加任何代码。
      throw ---人为编程实现抛出异常。
 
      如果需要在程序中自行抛出异常,应使用throw语句。
 
      throw语句可以单独使用,throw语句抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常实例。
  • 如果throw语句抛出的异常是Checked异常,则该throw语句要么处于try块里,显式捕获该异常,要么放在一个带throws声明抛出的方法中,即把该异常交给该方法的调用者处理。
  • 如果throw语句抛出的异常是Runtime异常,则该语句无须放在try块中,也无须放在带throws声明抛出的方法中,程序既可以显示使用try...catch来捕获并处理该异常,也可以完全不理会该异常,把该异常交给该方法调用者处理。
 
      throws-- 用在方法签名中,用于声明该方法可能抛出的异常,要求谁调用谁处理这个异常。主方法上也可以使用 throws 抛出。
      如果在主方法上使用了 throws 抛出,就表示在主方法里面可以不用强制性进行异常处理,如果出现 了异常,就交给 JVM 进行默认处理,则此时会导致程序中断执行
     如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明
package yichang;

import java.util.Scanner;

public class D8 {
	public static void main(String[] args) throws Exception {
		Scanner sc = new Scanner(System.in);
		String a = sc.nextLine();
		if ("yuan".equals(a)) {
			throw new RuntimeException("dddd");// 编码产生异常,其中构造器参数就是异常信息
		}
		System.out.println("键盘录入为" + a);
		System.out.println("程序终止。");

	}
}
catch 语句
   在 catch 语句块中是对异常进行处理的代码,每个 try 语句块可以伴随一个或多个 catch 语句,用于处理可能产生的不 同类型的异常对象,同时允许异常的继续抛出。
   catch 只匹配成功一次即可,注意 不是最佳匹配 ,例如交换 Exception NumberFormatException 的位置,这里就 会语法报错,报错的提示信息为
   Unreachable catch block for NumberFormatException. It is already handled by the catch block for Exception
   含义是 catch(NumberFormatException e) 是不可达语句,
   NumberFormatException Exception 的子类。
强调:在编写多个 catch 时,小异常一定在大异常之前 ,顺序执行不然会不可达。
Integer kk=null; 
try{
  String str="123.456"; 
  kk=Integer.parseInt(str);
  System.out.println("数据转换结束");
} catch(NumberFormatException e){ 
  System.out.println("数据格式错误!"); 
//继续抛出异常,不再是直接消费处理掉了,导致的结果是try之后的代码并没有得到执行
  throw new Exception(e.getMessage()); 
//throw e;在用在方法上throws声明抛出,因为 NumberFormatException是运行时异常
//throw new Exception(""); 需要在方法上声明抛出,因为Exception是受检型异常 
} catch(Exception e){ 
  System.out.println("出现了错误:"+e.getMessage()); 
}
  System.out.println("转换结果为"+kk);
  • catch中声明的异常对象封装了异常发生的信息,在catch语句块中可以使用这个对象的一些方法获取这些信息getMessage():String
  • 用于获取有关异常事件的信息,一般是异常信息的描述,例如【For input string: "123.456"
  • toString():String,输出格式为【java.lang.NumberFormatException: For input string: "123.456"
  • printStackTrace():void用来跟踪异常事件发生时执行堆栈的内容,注意:这里的输出默认采用错误流
  • System.err进行输出,如果还使用了System.out进行输出,则不能保证显示顺序  
  • 注意:使用 printStackTrace ()输出调用栈使用的是 System.err 输出报错信息,不是编程使用的 System.out ,所以输
    出顺序有可能和预计不一致
常见的 3 种输出异常的用法
  • System.out.println(e);  //java.lang.ArithmeticException: / by zero
    System.out.println(e.getMessage()); // / by zero
    e.printStackTrace(); 调用栈

JDK1.7引入多异常捕获

       大部分情况下可能会出现多种不同异常但是处理方法一致时 , 注意这多个异常类型之间没有继承关系。
 
       如果有继承关 系则应该写成 try{}catch( 父类型 e){} 即可
try{
   int k=0; system.out.println(10/k);
}catch(ArithmeticException e){ 
   System.out.println(e); 
}catch(NullPointerException e){
   System.out.println(e); 
}

//两次捕捉异常的处理是一样的,就可以将两个异常卸载一个catch中,其中多个异常类型之间使用|分割

try{
   int k=0; 
   system.out.println(10/k);
}catch(ArithmeticException | NullPointerException e){//含义和上面的一致
   System.out.println(e);
 }
try{} catch(IndexOutOfBoundException | NumberFormatException | ArithmeticException e){ }
这里需要注 意的是:捕获一种异常时,异常对象没有 final 的含义,但是多种异常时隐含了 final 含义,所以不能修改对象引用 [ ]
 
package yichang;

public class D09 {
	public static void main(String[] args) {
		
		try{
			int k = 0;
			System.out.println(10 / k);
		}catch(ArithmeticException e){
			System.out.println(e);
			e=new ArithmeticException("YYYYY"); //注意按照Java变量的规则,这里的类型不能变,所以可以new当前类型,也可以子类型 ; 
			throw e;
		}catch(NullPointerException e){ 
			System.out.println(e);
		}
	}
	
}

 

package yichang;

public class D10 {
	public static void main(String[] args) {
		try {
			int k = 0;
			System.out.println(10 / k);
		} catch (ArithmeticException | NullPointerException e) { // 要求异常类型之间不能有继承关系,如果有继承 关系应该只写大异常类型即可
			System.out.println(e);
			// e=new ArithmeticException("yyyy"); //错的。所以不能修改对象引用
			throw e;
		}
	}
}
finally 语句
 
   finally 语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分以前,能够对程序的状态作统一 的管理。
   无论 try 所指定的程序块是否抛出异常, finally 所指定的代码都要执行。
   try 可以没有 catch 而直接使用 finally ,当然在方法上声明抛出。

  

 编码练习:  要求输入一个合法的字符串类型的整数,进行数据类型转换,如果数据不合法则中断程序执行,并进行提示。 

package yichang;

import java.util.Scanner;

public class D11 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入一个整数");
		String ss = sc.nextLine();
		try {
			int kk = Integer.parseInt(ss.trim());
			System.out.println("输入数据正确,具体值为:" + kk);
		} catch (NumberFormatException e) {
			System.out.println("输入的数据格式错误!");
		} catch (Exception e) {
			System.out.println("其它错误:" + e.getMessage());
		}finally{ //不管陷阱代码中是否出现异常,是否执行了catch语句,finally语句块一定要执行 
                        System.out.println("finally...."); 
                }
                        System.out.println("end pp....");//这个语句有可能不执行,但是finally是无论如何都会被执行。
               //典型案例去掉所有的catch语句,当出现异常时finally还是执行了的,但是这个语句没有执行
	}
}
    通常在 finally 语句中可以进行资源的清除工作,例如关闭打开的文件,删除临时文件等。注意 Java 的垃圾回收机制 只能回收再堆内存中对象所占用的内存,而不会回收任何物理资源(如数据库连接、网络连接和磁盘文件等)。
 
特殊情况导致 finally 执行出现问题
 
   在前边的代码中使用 System.exit(int) 退出应用
 
   System.exit(int status) 这个方法是用来结束当前正在运行中的 java 虚拟机。
  • status是非零参数,那么表示是非正常退出。
  • System.exit(0)是正常退出程序,而System.exit(1)或者说非0表示非正常退出程序。
package yichang;

public class D12 {
	public static void main(String[] args) {
		try {
		int a = 10;
		System.out.println(10/a);
		System.exit(0);//無條件立即终止执行
		}finally {//按道理无论try是否抛出异常都要执行finally,此时finally却没被执行
			System.out.println("finally 语句块!");
		}
	}

}
/*
输出结果:
1
*/
  • 程序所在的线程死亡或者cpu关闭
  • 如果在finally代码块中的操作又产生异常,则该finally代码块不能完全执行结束
package yichang;

import java.util.Scanner;

public class D13 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入一个整数");
		String ss = sc.nextLine();
		try {
			int kk = Integer.parseInt(ss.trim());//strim()方法去掉输入前后的空格,如果输入错误,是NumberFormatException错误
			System.out.println("输入数据正确,具体值为:" + kk);
			System.exit(0);//终止了finally语句块的执行
		} finally {
			int kk = 0;
			System.out.println(10 / kk); // 这里出现异常,提供提示为ArithmeticException, 而没有上面出现的NumberFormatException 了
                        System.out.println("finally代码块执行结束。");//不执行,finally代码块不能完全执行结束 
		}
	}
}
考核点:finally块和return
 
package yichang;

import java.util.Scanner;

public class D14 {
	public  int yuan() {
		try {
			Scanner sc = new Scanner(System.in);
			System.out.println(10 / sc.nextInt());// 可能出现ArithmeticException异常和NumberFormatException异常
			System.out.println("try...");//出现上述两种输入异常 此语句不会执行
			return 0;// 由于有finally语句,所以这里的return不会立即执行 ,要等finally语句执行后才能返回

		} catch (Exception e) {
			System.out.println("catch...");
			return 1;
		} finally {
			System.out.println("finally...");
			return 2;//这里的return会替换前面的return结果,不管是否异常都是 2。

		}
	}
	public static void main(String[] args) {
		D14 a = new D14();
	        System.out.println(a.yuan());
	}
}
考点: finally final finalize 的区别
 

一、final :

1、修饰符(关键字) 如果一个类被声明为final,意味着它不能再派生新的子类,不能作为父类被继承。因此一个类不能及被声明为abstract,又被声明为final的。

2、将变量或方法声明为final,可以保证他们使用中不被改变。被声明为final的变量必须在声明时给定初值,而以后的引用中只能读取,不可修改,被声明为final的方法也同样只能使用,不能重载。

二、finally:

在异常处理时提供finally块来执行清楚操作。

三、finalize:

是方法名。java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除之前做必要的清理工作。这个方法是在垃圾收集器在确定了,被清理对象没有被引用的情况下调用的。

finalize是在Object类中定义的,因此,所有的类都继承了它。子类可以覆盖finalize()方法,来整理系统资源或者执行其他清理工作。

    Java 的异常处理机制使得异常事件能够沿着被调用的顺序向前寻找,只要找到符合该异常种类的异常处理程序,就会进行异常处理逻辑的执行,并且被消费掉,不会继续
 
查找。 容易出现的一个编码问题:隐藏异常
如果catch代码块里面为空就会隐藏异常。
catch(Exception e){
//异常被隐藏了
}
最佳异常相关编程实践
 
1 、不要在 fianlly 中使用 return
2 、不要在 finally 中抛出异常
3 、减轻 finally 的任务,不要在 finally 中做一些其它的事情, finally 块仅仅用来释放资源是最合适的。
4 、将尽量将所有的 return 写在函数的最后面,而不是 try … catch … finally 中 。
 
异常处理建议规则
 
1 、不要过度使用异常,不要把异常当做不同的逻辑分支对待
2 、不要使用过于庞大的 try
3 、避免使用 catch all 语句 try{}catch(Throwable t){}
4 、坚决不要忽略捕获的异, 坚决不允许 catch 块中内容为空

自定义异常

  • 所有异常都必须是 Throwable 的子类。
  • 如果希望写一个检查性异常类,则需要继承 Exception 类。只继承Exception 类来创建的异常类是检查性异常类。
  • 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
  • 一个异常类和其它任何类一样,包含有变量和方法。
       通过继承 java.lang.Exception 类【受检型异常】或者 RuntimeException 【非受检型异常】声明自定义异常类 【也允许继承 Throwable 或者 Exception 的子类】。
 
例如因为业务导致可能出现的问题账户余额不足问题。
 
package yichang;

public class BankAccount { //银行账户类
	//balance为余额,number为卡号
	private double balance;
	private long number;
	public BankAccount(long number) { //构造方法
		this.number = number;
	}
	
	public void deposit(int amounts) {//deposit(存款)这是个存钱的动作,方法
		this.balance += amounts;
	}
	public void withdraw(int amounts)throws InsufficientFundsException {//withdraw取钱方法,throws该方法可能抛出的异常
		if(amounts < this.balance)
		this.balance -= amounts;	
		else {
			double needs = amounts - this.balance;//是个正数,说明了还欠多少钱
	        throw new InsufficientFundsException(needs);//抛出具体的对象
		}
	}
	public double getbalance() {//获取当前余额值
		return this.balance;
	}
	public long getnumber() {//获取卡号
		return this.number;
	}

}
package yichang;

//资金不足异常类 InsufficientFundsException
public class InsufficientFundsException extends Exception {

	private double amounts; // 此处的amounts(金额)用来储存当出现异常(取出钱多于余额时)所缺乏的钱.

	public InsufficientFundsException(double amounts) {// 构造函数给金额amounts赋值
		this.amounts = amounts;
	}

	public double getamounts() {//获取当前金额,就是知道现在有多少钱
		return amounts;
	}

}

 

package yichang;

public class BankDemo {//银行的一个账户小样类
	public static void main(String[] args) {
		BankAccount a = new BankAccount(1112138);
		System.out.println("存款五万元!");
		a.deposit(50000);//调用存款方法存款五万元
		try {
			System.out.println("\n取款三万元");
			a.withdraw(30000);//调用方法取款三万元
			System.out.println("\n再取三万块");
			a.withdraw(30000);
			
		}catch(InsufficientFundsException e) {
			System.out.println("余额不足还差"+e.getamounts());
			
			
		}
	}

}

输出结果:

存款五万元!

取款三万元。

再取三万块。
余额不足还差10000.0

通用异常

在Java中定义了两种类型的异常和错误。

  • JVM(Java虚拟机) 异常:由 JVM 抛出的异常或错误。例如:NullPointerException 类,ArrayIndexOutOfBoundsException 类,ClassCastException 类。
  • 程序级异常:由程序或者API程序抛出的异常。例如 IllegalArgumentException 类,IllegalStateException 类。

                   世界上的意外不可穷举,程序可能发生的异常总是大于程序员所能考虑的意外!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值