异常概述

什么是异常,java提供异常处理机制有什么用?
以下程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常

java语言是很完善的语言,提供了异常的处理方式,以下程序执行过程中出现了不正常的情况,java把该异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对程序进行修改,让程序更加的健壮。

什么是异常:程序执行过程中的不正常情况
异常的作用:增强程序的健壮性

以下程序执行控制台出现了:

Exception in thread "main" java.lang.ArithmeticException: / by zeroat com.bjpowernode.javase.exception.ExceptionTest01.main(ExceptionTest01.java:14)

这个信息被我们称为:异常信息。这个信息是JVM打印的。

public class ExceptionTest01 {public static void main(String[] args) {int a = 10;int b = 0;// 实际上JVM在执行到此处的时候,会new异常对象:new ArithmeticException("/ by zero");// 并且JVM将new的异常对象抛出,打印输出信息到控制台了。int c = a / b;System.out.println(a + "/" + b + "=" + c);// 此处运行也会创建一个:ArithmeticException类型的异常对象。//System.out.println(100 / 0);// 我观察到异常信息之后,对程序进行修改,更加健壮。/*int a = 10;int b = 2;if(b == 0) {System.out.println("除数不能为0");return;}// 程序执行到此处表示除数一定不是0int c = a / b;System.out.println(a + "/" + b + "=" + c);*/}
}

java语言中异常是以什么形式存在的呢?

  • 异常在Java中以类的形式存在,每一个异常类都可以创建异常对象。

  • 异常对应的现实生活中是怎样的?

      火灾(异常类):2008年8月8日,小明家着火了(异常对象)2008年8月9日,小刚家着火了(异常对象)2008年9月8日,小红家着火了(异常对象)类是:模板。对象是:实际存在的个体。钱包丢了(异常类):2008年1月8日,小明的钱包丢了(异常对象)2008年1月9日,小芳的钱包丢了(异常对象)....
    
public class ExceptionTest02 {public static void main(String[] args) {// 通过“异常类”实例化“异常对象”NumberFormatException nfe = new NumberFormatException("数字格式化异常!");// java.lang.NumberFormatException: 数字格式化异常!System.out.println(nfe);// 通过“异常类”创建“异常对象”NullPointerException npe = new NullPointerException("空指针异常发生了!");//java.lang.NullPointerException: 空指针异常发生了!System.out.println(npe);}
}
  • 【Java的异常处理机制】

    1.1异常在java中以类和对象的形式存在。那么异常的集成结构是怎样的?

    我们可以使用UML图来描述一下继承结构。
    画UML图由有很多工具,例如:Rational Rose(收费的)、startUML等…

    1.1.1 什么是UML?有什么用?
    UML是一种统一建模语言。
    一种图标式语言(画图的)
    UML不是只有java中使用,只要是面向对象的编程语言,都有UML。
    一般画UML图的都是软件架构师或者说是系统分析师,这些级别的人员使用的。
    软件设计人员使用UML。

    在UML图中可以描述类和类之间的关系,程序执行的流程,对象的状态等。

    盖大楼和软件开发一样,一个道理:
    盖楼之前,会先由建筑师画图纸。图纸上一个一个符号都是标准符号。
    这个图纸画完,只要是搞建筑的都能看懂,因为这个图纸上标注的这些符号都是一种“标准的语言”

    在Java软件开发当中,软件分析师/设计师负责设计类,Java软件开发人员必须要能看懂。

      ObjectObject下有Throwable(可抛出的)Throwable下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的)Exception下有两个分支:Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错,因此得名编译时异常。)。RuntimeException:运行时异常。(在编写程序阶段程序员可以预先处理,也可以不管,都行。)
    

1.2 编译时异常和运行时异常,都是发生在运行阶段。编译阶段异常是不会发生的。

编译时异常因为什么而得名???

因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,因此得名。
所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象。
因为异常的发生就是new异常对象。

1.3编译时异常和运行时异常的区别??

编译时异常一般发生的概率比较高。

举个栗子:
你看到外面下雨了,倾盆大雨的。
你出门之前会预料到:如果不打伞,我可能会生病(生病是一种异常)
而且这个异常发生的概率很高,所以我们出门之前要拿一把伞。
“拿一把伞”就是对“生病异常”发生之前的一种处理方式。

对于一些发生概率较高的异常,需要在运行之前对其进行预处理。

运行时异常一般发生的概率比较低。

举个栗子:
小明走在大街上,可能会被天上的飞机轮子砸到。
被飞机轮子砸到也算一种异常
但是这种异常发生的概率较低
在出门之前你没必要提前对这种发生概率较低的异常进行预处理
如果你预处理这种异常,你将活的很累

假设你在出门之前,你把能够发生的异常都预先处理,你这个人会更加的安全,但是你这个人活的很累。

假设java中没有对异常进行划分,没有分为:编译时异常和运行时异常,所有的异常都需要在编写程序阶段对其进行预处理,将会是怎样的效果?
首先,如果这样的话,程序肯定是绝对安全的。
但是程序员编写程序太累,代码到处都是处理异常的代码。

1.4编译时异常还有其他名字:
受检异常:CheckedException
受控异常

1.5运行时异常还有其他名字:
未受检异常:UnCheckedException
非受控异常

1.6再次强调:所有异常都是发生在运行阶段的。

1.7Java语言中对异常的处理包括两种方式:

第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级。
谁调用我,我就抛给谁。抛给上一级。

第二种方式:使用try…catch语句进行异常的捕捉。
这件事发生了,谁也不知道,因为我给抓住了。

 举个例子:我是某集团的一个销售员,因为我的失误,导致公司损失了1000元,“损失1000元”这可以看做是一个异常发生了。我有两种处理方式,第一种方式:我把这件事告诉我的领导【异常上抛】第二种方式:我自己掏腰包把这个钱补上。【异常的捕捉】张三 --> 李四 ---> 王五 --> CEO

【思考:】
异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式。

1.8注意:
Java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果。终止java程序的执行。

public class ExceptionTest03 {public static void main(String[] args) {/*程序执行到此处发生了ArithmeticException异常,底层new了一个ArithmeticException异常对象,然后抛出了,由于是main方法调用了100 / 0,所以这个异常ArithmeticException抛给了main方法,main方法没有处理,将这个异常自动抛给了JVM。JVM最终终止程序的执行。ArithmeticException 继承 RuntimeException,属于运行时异常。在编写程序阶段不需要对这种异常进行预先的处理。*/System.out.println(100 / 0);// 这里的HelloWorld没有输出,没有执行。System.out.println("Hello World!");}
}

以下代码报错的原因是什么?

因为doSome()方法声明位置上使用了:throws ClassNotFoundException
而ClassNotFoundException是编译时异常。必须编写代码时处理,没有处理 编译器报错。

public class ExceptionTest04 {public static void main(String[] args) {// main方法中调用doSome()方法// 因为doSome()方法声明位置上有:throws ClassNotFoundException// 我们在调用doSome()方法的时候必须对这种异常进行预先的处理。// 如果不处理,编译器就报错。//编译器报错信息: Unhandled exception: java.lang.ClassNotFoundException//doSome();}/*** doSome方法在方法声明的位置上使用了:throws ClassNotFoundException* 这个代码表示doSome()方法在执行过程中,有可能会出现ClassNotFoundException异常。* 叫做类没找到异常。这个异常直接父类是:Exception,所以ClassNotFoundException属于编译时异常。* @throws ClassNotFoundException*/public static void doSome() throws ClassNotFoundException{System.out.println("doSome!!!!");}}
public class ExceptionTest05 {// 第一种处理方式:在方法声明的位置上继续使用:throws,来完成异常的继续上抛。抛给调用者。// 上抛类似于推卸责任。(继续把异常传递给调用者。)/*public static void main(String[] args) throws ClassNotFoundException {doSome();}*/// 第二种处理方式:try..catch进行捕捉。// 捕捉等于把异常拦下了,异常真正的解决了。(调用者是不知道的。)public static void main(String[] args) {try {doSome();} catch (ClassNotFoundException e) {e.printStackTrace();}}public static void doSome() throws ClassNotFoundException{System.out.println("doSome!!!!");}}

处理异常的第一种方式:
在方法声明的位置上使用throws关键字抛出,谁调用我这个方法,我就抛给谁。抛给调用者来处理。
这种处理异常的态度:上报。

处理异常的第二种方式:
使用try…catch语句对异常进行捕捉。
这个异常不会上报,自己把这个事儿处理了。
异常抛到此处为止,不再上抛了。

【注意:】
只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行。
另外需要注意,try语句块中的某一行出现异常,该行后面的代码不会执行。
try…catch捕捉异常之后,后续代码可以执行。

在以后的开发中,处理编译时异常,应该上报还是捕捉呢??怎么选??
如果希望调用者来处理,选择throws上报。
其他情况使用捕捉的方式。

public class ExceptionTest06 {// 一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM。JVM只有终止。// 异常处理机制的作用就是增强程序的健壮性。怎么能做到,异常发生了也不影响程序的执行。所以// 一般main方法中的异常建议使用try..catch进行捕捉。main就不要继续上抛了。/*public static void main(String[] args) throws FileNotFoundException {System.out.println("main begin");m1();System.out.println("main over");}*/public static void main(String[] args) {// 100 / 0这是算术异常,这个异常是运行时异常,你在编译阶段,可以处理,也可以不处理。编译器不管。//System.out.println(100 / 0); // 不处理编译器也不管// 你处理也可以。/*try {System.out.println(100 / 0);} catch(ArithmeticException e){System.out.println("算术异常了!!!!");}*/System.out.println("main begin");try {// try尝试m1();// 以上代码出现异常,直接进入catch语句块中执行。System.out.println("hello world!");} catch (FileNotFoundException e){ // catch后面的好像一个方法的形参。// 这个分支中可以使用e引用,e引用保存的内存地址是那个new出来异常对象的内存地址。// catch是捕捉异常之后走的分支。// 在catch分支中干什么?处理异常。System.out.println("文件不存在,可能路径错误,也可能该文件被删除了!");System.out.println(e); //java.io.FileNotFoundException: D:\course\01-课\学习方法.txt (系统找不到指定的路径。)}// try..catch把异常抓住之后,这里的代码会继续执行。System.out.println("main over");}private static void m1() throws FileNotFoundException {System.out.println("m1 begin");m2();// 以上代码出异常,这里是无法执行的。System.out.println("m1 over");}// 抛别的不行,抛ClassCastException说明你还是没有对FileNotFoundException进行处理//private static void m2() throws ClassCastException{// 抛FileNotFoundException的父对象IOException,这样是可以的。因为IOException包括FileNotFoundException//private static void m2() throws IOException {// 这样也可以,因为Exception包括所有的异常。//private static void m2() throws Exception{// throws后面也可以写多个异常,可以使用逗号隔开。//private static void m2() throws ClassCastException, FileNotFoundException{private static void m2() throws FileNotFoundException {System.out.println("m2 begin");// 编译器报错原因是:m3()方法声明位置上有:throws FileNotFoundException// 我们在这里调用m3()没有对异常进行预处理,所以编译报错。// m3();m3();// 以上如果出现异常,这里是无法执行的!System.out.println("m2 over");}private static void m3() throws FileNotFoundException {// 调用SUN jdk中某个类的构造方法。// 这个类还没有接触过,后期IO流的时候就知道了。// 我们只是借助这个类学习一下异常处理机制。// 创建一个输入流对象,该流指向一个文件。/*编译报错的原因是什么?第一:这里调用了一个构造方法:FileInputStream(String name)第二:这个构造方法的声明位置上有:throws FileNotFoundException第三:通过类的继承结构看到:FileNotFoundException父类是IOException,IOException的父类是Exception,最终得知,FileNotFoundException是编译时异常。错误原因?编译时异常要求程序员编写程序阶段必须对它进行处理,不处理编译器就报错。*///new FileInputStream("D:\\course\\01-开课\\学习方法.txt");// 我们采用第一种处理方式:在方法声明的位置上使用throws继续上抛。// 一个方法体当中的代码出现异常之后,如果上报的话,此方法结束。new FileInputStream("D:\\course\\01-课\\学习方法.txt");System.out.println("如果以上代码出异常,这里会执行吗??????????????????不会!!!");}
}

深入try…catch

  • catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型。
  • catch可以写多个。建议catch的时候,精确的一个一个处理,这样有利于程序的调试。
  • catch写多个的时候,从上到下,必须遵循从小到大。
public class ExceptionTest07 {/*public static void main(String[] args) throws Exception, FileNotFoundException, NullPointerException {}*//*public static void main(String[] args) throws Exception {}*/public static void main(String[] args) {//编译报错/*try {FileInputStream fis = new FileInputStream("D:\\course\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");} catch(NullPointerException e) {}*//*try {FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");System.out.println("以上出现异常,这里无法执行!");} catch(FileNotFoundException e) {System.out.println("文件不存在!");}System.out.println("hello world!");*//*try {FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");} catch(IOException e) { // 多态:IOException e = new FileNotFoundException();System.out.println("文件不存在!");}*//*try {FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");} catch(Exception e) { // 多态:Exception e = new FileNotFoundException();System.out.println("文件不存在!");}*//*try {//创建输入流FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");//读文件fis.read();} catch(Exception e) { //所有的异常都走这个分支。System.out.println("文件不存在!");}*//*try {//创建输入流FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");//读文件fis.read();} catch(FileNotFoundException e) {System.out.println("文件不存在!");} catch(IOException e){System.out.println("读文件报错了!");}*/// 编译报错。/*try {//创建输入流FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");//读文件fis.read();} catch(IOException e){System.out.println("读文件报错了!");} catch(FileNotFoundException e) {System.out.println("文件不存在!");}*/// JDK8的新特性!try {//创建输入流FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");// 进行数学运算System.out.println(100 / 0); // 这个异常是运行时异常,编写程序时可以处理,也可以不处理。} catch(FileNotFoundException | ArithmeticException | NullPointerException e) {System.out.println("文件不存在?数学异常?空指针异常?都有可能!");}}
}

异常对象有两个非常总要的方法

获取异常简单的描述信息:

String msg = exception.getMessage();

打印异常追踪的堆栈信息:

exception.printStackTrace();
public class ExceptionTest08 {public static void main(String[] args) {// 这里只是为了测试getMessage()方法和printStackTrace()方法。// 这里只是new了异常对象,但是没有将异常对象抛出。JVM会认为这是一个普通的java对象。NullPointerException e = new NullPointerException("空指针异常fdsafdsafdsafds");// 获取异常简单描述信息:这个信息实际上就是构造方法上面String参数。String msg = e.getMessage(); //空指针异常fdsafdsafdsafdsSystem.out.println(msg);// 打印异常堆栈信息// java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印的。e.printStackTrace();for(int i = 0; i < 1000; i++){System.out.println("i = " + i);}System.out.println("Hello World!");}
}

异常对象的两个方法:

String msg = e.getMessage();
e.printStackTrace(); // 一般都是使用这个

我们以后查看异常的追踪信息,我们应该怎么看,可以快速的调式程序呢??

异常信息追踪信息,从上往下一行一行的看。
但是需要注意的是:SUN写的代码就不用看了(看包名就知道是自己的还是SUN的)。
主要的问题是出现在自己编写的代码上。

public class ExceptionTest09 {public static void main(String[] args) {try {m1();} catch (FileNotFoundException e) {// 获取异常的简单描述信息String msg = e.getMessage();System.out.println(msg); //C:\jetns-agent.jar (系统找不到指定的文件。)//打印异常堆栈追踪信息!!!//在实际的开发中,建议使用这个。养成好习惯!// 这行代码要写上,不然出问题你也不知道!//e.printStackTrace();/*java.io.FileNotFoundException: C:\jetns-agent.jar (系统找不到指定的文件。)at java.base/java.io.FileInputStream.open0(Native Method)at java.base/java.io.FileInputStream.open(FileInputStream.java:213)at java.base/java.io.FileInputStream.<init>(FileInputStream.java:155)at java.base/java.io.FileInputStream.<init>(FileInputStream.java:110)at com.bjpowernode.javase.exception.ExceptionTest09.m3(ExceptionTest09.java:31)at com.bjpowernode.javase.exception.ExceptionTest09.m2(ExceptionTest09.java:27)at com.bjpowernode.javase.exception.ExceptionTest09.m1(ExceptionTest09.java:23)at com.bjpowernode.javase.exception.ExceptionTest09.main(ExceptionTest09.java:14)因为31行出问题导致了27行27行出问题导致23行23行出问题导致14行。应该先查看31行的代码。31行是代码错误的根源。*/}// 这里程序不耽误执行,很健壮。《服务器不会因为遇到异常而宕机。》System.out.println("Hello World!");}private static void m1() throws FileNotFoundException {m2();}private static void m2() throws FileNotFoundException {m3();}private static void m3() throws FileNotFoundException {new FileInputStream("C:\\jetns-agent.jar");}
}

关于try…catch中的finally子句:

  • 在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。
    finally子句必须和try一起出现,不能单独编写。

  • finally语句通常使用在哪些情况下呢??
    通常在finally语句块中完成资源的释放/关闭。
    因为finally中的代码比较有保障。
    即使try语句块中的代码出现异常,finally中代码也会正常执行。

public class ExceptionTest10 {public static void main(String[] args) {FileInputStream fis = null; // 声明位置放到try外面。这样在finally中才能用。try {// 创建输入流对象fis = new FileInputStream("D:\\course\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");// 开始读文件....String s = null;// 这里一定会出现空指针异常!s.toString();System.out.println("hello world!");// 流使用完需要关闭,因为流是占用资源的。// 即使以上程序出现异常,流也必须要关闭!// 放在这里有可能流关不了。//fis.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch(IOException e){e.printStackTrace();} catch(NullPointerException e) {e.printStackTrace();} finally {System.out.println("hello 浩克!");// 流的关闭放在这里比较保险。// finally中的代码是一定会执行的。// 即使try中出现了异常!if (fis != null) { // 避免空指针异常!try {// close()方法有异常,采用捕捉的方式。fis.close();} catch (IOException e) {e.printStackTrace();}}}System.out.println("hello kitty!");}
}

finally语句:
放在finally语句块中的代码是一定会执行的【再次强调!!!】

public class ExceptionTest11 {public static void main(String[] args) {/*try和finally,没有catch可以吗?可以。try不能单独使用。try finally可以联合使用。以下代码的执行顺序:先执行try...再执行finally...最后执行 return (return语句只要执行方法必然结束。)*/try {System.out.println("try...");return;} finally {// finally中的语句会执行。能执行到。System.out.println("finally...");}// 这里不能写语句,因为这个代码是无法执行到的。//System.out.println("Hello World!");}
}
/*
finally*/
public class ExceptionTest12 {public static void main(String[] args) {try {System.out.println("try...");// 退出JVMSystem.exit(0); // 退出JVM之后,finally语句中的代码就不执行了!} finally {System.out.println("finally...");}}
}

finally面试题:

public class ExceptionTest13 {public static void main(String[] args) {int result = m();System.out.println(result); //100}/*java语法规则(有一些规则是不能破坏的,一旦这么说了,就必须这么做!):java中有一条这样的规则:方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法!)java中海油一条语法规则:return语句一旦执行,整个方法必须结束(亘古不变的语法!)*/public static int m(){int i = 100;try {// 这行代码出现在int i = 100;的下面,所以最终结果必须是返回100// return语句还必须保证是最后执行的。一旦执行,整个方法结束。return i;} finally {i++;}}
}/*
反编译之后的效果
public static int m(){int i = 100;int j = i;i++;return j;
}*/

final、finally、finalize有什么区别??

final关键字

  • final修饰的类无法继承
  • final修饰的方法无法覆盖
  • final修饰的变量不能重新赋值

finally关键字

  • 和try一起联合使用
  • finally语句块中的代码是必须执行的

finalize 标识符

  • 是一个Object类中的方法名
  • 这个方法是由垃圾回收器GC负责调用的
public class ExceptionTest14 {public static void main(String[] args) {// final是一个关键字。表示最终的。不变的。final int i = 100;//i = 200;// finally也是一个关键字,和try联合使用,使用在异常处理机制中// 在fianlly语句块中的代码是一定会执行的。try {} finally {System.out.println("finally....");}// finalize()是Object类中的一个方法。作为方法名出现。// 所以finalize是标识符。// finalize()方法是JVM的GC垃圾回收器负责调用。Object obj;}
}// final修饰的类无法继承
final class A {// 常量。public static final double MATH_PI = 3.1415926;
}class B {// final修饰的方法无法覆盖public final void doSome(){}
}

自定义异常

  • SUN提供的JDK内置的异常肯定是不够用的。在实际的开发中,有很多业务,这些业务出现异常之后,JDK中都是没有的。和业务挂钩的。那么异常类我们程序员可以自己定义吗?

  • Java中怎么自定义异常呢?

    两步:
    第一步:编写一个类继承Exception或者RuntimeException。
    第二步:提供两个构造方法,一个无参数的,一个带有String参数的。
    死记硬背!!

public class MyException extends Exception{ // 编译时异常public MyException(){}public MyException(String s){super(s);}
}/*
public class MyException extends RuntimeException{ // 运行时异常}*/
public class ExceptionTest15 {public static void main(String[] args) {// 创建异常对象(只new了异常对象,并没有手动抛出)MyException e = new MyException("用户名不能为空!");// 打印异常堆栈信息e.printStackTrace();// 获取异常简单描述信息String msg = e.getMessage();System.out.println(msg);}
}

编写程序,使用一维数组,模拟栈数据结构

要求:1.这个栈可以存储java中的任何引用类型的数。2.在栈中提供push方法模拟压栈。(栈满了,要有提示信息。)3.在中提供pop方法模拟弹栈。(栈空了,也要有提示信息。)4.编写测试程序,new栈对象,调用push、pop方法来模拟压栈弹栈的动作。5.假设栈的默认初始化容量是10,(请注意无参数构造方法的编写方式。)
public class MyStack {// 向栈当中存储元素,我们这里使用一维数组模拟。存到栈中,就表示存储到数组中。// 因为数组是我们学习java的第一个容器。// 为什么选择Object类型数组?因为这个栈可以存储java中的任何引用类型的数据// new Animal()对象可以放进去,new Person()对象也可以放进去。因为Animal和Person的超级父类就是Object。// 包括String也可以存储进去。因为String父类也是Object。private Object[] elements;// 栈帧,永远指向栈顶部元素// 那么这个默认初始值应该是多少。注意:最初的栈是空的,一个元素都没有。//private int index = 0; // 如果index采用0,表示栈帧指向了顶部元素的上方。//private int index = -1; // 如果index采用-1,表示栈帧指向了顶部元素。private int index;/*** 无参数构造方法。默认初始化栈容量10.*/public MyStack() {// 一维数组动态初始化// 默认初始化容量是10.this.elements = new Object[10];// 给index初始化this.index = -1;}/*** 压栈的方法* @param obj 被压入的元素*/public void push(Object obj) throws MyStackOperationException {if(index >= elements.length - 1){// 改良之前//System.out.println("压栈失败,栈已满!");//return;// 创建异常对象//MyStackOperationException e = new MyStackOperationException("压栈失败,栈已满!");// 手动将异常抛出去!//throw e; //这里捕捉没有意义,自己new一个异常,自己捉,没有意义。栈已满这个信息你需要传递出去。// 合并(手动抛出异常!)throw new MyStackOperationException("压栈失败,栈已满!");}// 程序能够走到这里,说明栈没满// 向栈中加1个元素,栈帧向上移动一个位置。index++;elements[index] = obj;// 在声明一次:所有的System.out.println()方法执行时,如果输出引用的话,自动调用引用的toString()方法。System.out.println("压栈" + obj + "元素成功,栈帧指向" + index);}/*** 弹栈的方法,从数组中往外取元素。每取出一个元素,栈帧向下移动一位。* @return*/public void pop() throws MyStackOperationException {if(index < 0){//System.out.println("弹栈失败,栈已空!");//return;throw new MyStackOperationException("弹栈失败,栈已空!");}// 程序能够执行到此处说明栈没有空。System.out.print("弹栈" + elements[index] + "元素成功,");// 栈帧向下移动一位。index--;System.out.println("栈帧指向" + index);}// set和get也许用不上,但是你必须写上,这是规矩。你使用IDEA生成就行了。// 封装:第一步:属性私有化,第二步:对外提供set和get方法。public Object[] getElements() {return elements;}public void setElements(Object[] elements) {this.elements = elements;}public int getIndex() {return index;}public void setIndex(int index) {this.index = index;}
}

/*** 栈操作异常:自定义异常!*/
public class MyStackOperationException extends Exception{ // 编译时异常!public MyStackOperationException(){}public MyStackOperationException(String s){super(s);}}

测试改良之后的MyStack
【注意:】
最后这个例子,是异常最重要的案例,必须掌握,自定义异常在实际开发中的应用。

public class ExceptionTest16 {public static void main(String[] args) {// 创建栈对象MyStack stack = new MyStack();// 压栈try {stack.push(new Object());stack.push(new Object());stack.push(new Object());stack.push(new Object());stack.push(new Object());stack.push(new Object());stack.push(new Object());stack.push(new Object());stack.push(new Object());stack.push(new Object());// 这里栈满了stack.push(new Object());} catch (MyStackOperationException e) {// 输出异常的简单信息。System.out.println(e.getMessage());}// 弹栈try {stack.pop();stack.pop();stack.pop();stack.pop();stack.pop();stack.pop();stack.pop();stack.pop();stack.pop();stack.pop();// 弹栈失败stack.pop();} catch (MyStackOperationException e) {System.out.println(e.getMessage());}}
}

之前在讲解方法覆盖的时候,当时遗留了一个问题?
重写之后的方法不能比重写之前的方法抛出更多(更广泛)的异常,可以更少。

class Animal {public void doSome(){}public void doOther() throws Exception{}
}class Cat extends Animal {// 编译正常。public void doSome() throws RuntimeException{}// 编译报错。/*public void doSome() throws Exception{}*/// 编译正常。/*public void doOther() {}*/// 编译正常。/*public void doOther() throws Exception{}*/// 编译正常。public void doOther() throws NullPointerException{}
}

【总结异常中的关键字】

  • 异常捕捉:

    try
    catch
    finally
    
  • throws 在方法声明位置上使用,表示上报异常信息给调用者。

  • throw 手动抛出异常。

下一篇:集合

Java进阶——异常相关推荐

  1. JAVA进阶开发之(异常类)

    保姆级别的异常类教学(附代码) 目录 1.什么是异常: 2. java语言中异常以什么形式存在的呢? 3.异常对应的现实生活中是怎样的? 4.异常处理机制 5.异常处理的具体方式 6.运行时异常编写程 ...

  2. 【02】Java进阶:09-冒泡排序、选择排序、二分查找、异常、异常的产生和处理、自定义异常、多线程

    day09[排序算法.异常.多线程基础] 今日内容 冒泡排序 选择排序 二分查找 异常处理 多线程基础 教学目标 能够理解冒泡排序的执行原理 能够理解选择排序的执行原理 能够理解二分查找的执行原理 能 ...

  3. Java进阶之对象克隆(复制)

    转载自   Java进阶之对象克隆(复制) 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bo ...

  4. JAVA进阶教学之(集合)

    目录 1.集合概述 2.集合存储的数据类型 3.不同的集合,底层都会对应不同的数据结构 4.集合继承结构图(部分接口和类) 5.Collection接口中常用的方法 6.Collection 集合迭代 ...

  5. Java进阶_3 注解、APT

    Java进阶_3 注解.APT 一.注解的概念 注解(Annotation) ​ 也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次.它可以声明在 ...

  6. java进阶基础---2.3---IO流的概念及示例

    小梁同学 の Java学习旅途 你好! 这是小梁同学使用 博客 所记录的文章笔记,作为一个初学者的从基础到未来的记录,如果你想和我一起在Java学习路程上坚持下去,欢迎你的关注与指正. 以下所有有关代 ...

  7. Java基础到Java进阶——Java小白的历练之路------从0到1,开卷!

    Java小白的历练之路------从0到1 title: Java Essay date: 2022-09-07 08:58:32 tags: Java notes 写在前面: 免责声明:本笔记来源自 ...

  8. Java 自学路线图之 Java 进阶自学

    文章目录 Java 自学路线图的第二阶段是 Java 语言进阶自学,在自学了第一阶段的 Java 基础自学后,大家对 Java 语言编程有了初步的了解和认识,建议在第一部分自学后整理一下自己的自学思路 ...

  9. java进阶第二讲-数组、String类

    java进阶第二讲-数组.String类 1 回顾一下Object Object中的方法:public native int hashCode();带有native关键字的方法调用的是底层C++的dl ...

最新文章

  1. 牛客网(剑指offer) 第十三题 调整数组顺序使奇数位于偶数前面
  2. Java笔记--实时更新
  3. [svc]mousedos网络批量部署xp
  4. app android切图工具,2018最强手机APP切图规范指南和切片要求
  5. python工具书推荐_希望更加深入了解python 有什么书可以推荐?
  6. 64位sql server 如何使用链接服务器连接Access
  7. Atitit SpringCloud 使用总结 目录 1.1. 启动一个服务注册中心EurekaServer 1 1.2. 三、创建一个服务提供者 (eureka client) 2 1.3. 创建
  8. 【Network】OVS VXLAN/GRE 实践
  9. VTD的官方help翻译-ROD部分(10~15章)
  10. win7黑苹果双系统隐藏Clover多余启动项
  11. vue姓名动态输入三种方式、前端密码加密
  12. matlab系统稳态误差终值,matlab求稳态误差
  13. 路由器的应用场所及作用
  14. 星载SAR的各项指标解读(史上最全)
  15. (转)转给入职新人得体会
  16. LENOVO的Y430P笔记本无线网卡BCM43142在ubuntu 14.04系统WIF上网不稳定
  17. Scrapy错误-no active project Unknown command: crawl
  18. 一度智信:拼多多开店必备条件
  19. 【译】TcMalloc: Thread-Caching Malloc
  20. 基于CANVAS与MD5的客户端生成验证码

热门文章

  1. 滑板、围棋与 Kindle
  2. 1976年 比尔·盖茨写给电脑爱好者的公开信
  3. 中投公司副总经理谢平:互联网金融风险更低
  4. 荣耀手表2鸿蒙推送时间,鸿蒙OS正式版推送时间确定!荣耀机型也有份,六月初全面升级...
  5. [USACO Jan08] 化装晚会
  6. Matlab从三维矩阵中取出一列并且reshape
  7. 外汇高概率一分钟交易系统
  8. 百度脑图,唯一不黑的百度产品
  9. Chapter 2 Docker镜像与容器
  10. 3D游戏角色动画(二)