java异常一篇搞定

1,762 阅读15分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

哈喽,大家好!我是Why,一名在读学生,目前刚刚开始进入自己的编程学习生涯。虽然学习起步较晚,但我坚信做了才有0或1的可能。学了一段时间以后也是选择在掘金上分享自己的日常笔记,也希望能够在众多道友的大家庭中打成一片。 本文主要讲解java异常,如果大家读后觉得有用的话,还请大家多多支持博主:欢迎 ❤️点赞👍、收藏⭐、留言💬 ✨✨✨个人主页:JinHuan

异常

 1、什么是异常,java提供异常处理机制有什么用?
     以下程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常
     java语言是很完善的语言,提供了异常的处理方式,以下程序执行过程中出现了不正常情况,
     java把该异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对
     程序进行修改,让程序更加的健壮。
 ​
     什么是异常:程序执行过程中的不正常情况。
     异常的作用:增强程序的健壮性。
 ​
 2、以下程序执行控制台出现了:
     Exception in thread "main" java.lang.ArithmeticException: / by zero
         at 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;
         }
         // 程序执行到此处表示除数一定不是0
         int c = a / b;
         System.out.println(a + "/" + b + "=" + c);
          */
     }
 }

异常的存在方式

 1、异常在java中以类的形式存在,每一个异常类都可以创建异常对象。
 
 2、异常对应的现实生活中是怎样的?
 火灾(异常类):
 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);
     }
 }

运行时异常实例

 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!!!!");
     }
 ​
 }
 ​

异常的处理方式

 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 ​
 /*
 处理异常的第一种方式:
     在方法声明的位置上使用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("如果以上代码出异常,这里会执行吗??????????????????不会!!!");
     }
 }
 ​
 ​
 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!!!!");
     }
 ​
 }
 ​

About Try-catch

 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 ​
 ​
 深入try..catch
     "1、catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型。
     "2、catch可以写多个。建议catch的时候,精确的一个一个处理。这样有利于程序的调试。
     "3、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(); //空指针异常fdsafdsafdsafds
         System.out.println(msg);
 ​
         // 打印异常堆栈信息
         // java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印的。
         e.printStackTrace();
 ​
         for(int i = 0; i < 1000; i++){
             System.out.println("i = " + i);
         }
 ​
         System.out.println("Hello World!");
     }
 }
 运行结果如下:

怎样查看异常并做处理

 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 ​
 /*
 我们以后查看异常的追踪信息,我们应该怎么看,可以快速的调试程序呢?
     异常信息追踪信息,从上往下一行一行看。
     但是需要注意的是: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");
     }
 }
 ​

Finally语句

     "1、在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。
         finally子句必须和try一起出现,不能单独编写。
 ​
     "2finally语句通常使用在哪些情况下呢?
         通常在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!");
 ​
     }
 }

Try和finally的连用

验证finally语句一定是最后执行的

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

关于Finally中的特例

 "注意,当退出JVM的时候,Finally语句就不会执行了"
 ​
 public class ExceptionTest12 {
     public static void main(String[] args) {
         try {
             System.out.println("try...");
             // 退出JVM
             System.exit(0); // 退出JVM之后,finally语句中的代码就不执行了!
         } finally {
             System.out.println("finally...");
         }
     }
 }
 ​

Finally易错点

 "试推测下列result的返回值
 public class Test {
         public static void main(String[] args) {
             int result = m();
             System.out.println(result); //猜测结果
         }
         public static int m(){
             int i = 100;
             try {
                return i;
             } finally {
                 i++;
                 System.out.println("Finally中的i"+i);
             }
         }
     }

分析

  "java语法规则(有一些规则是不能破坏的,一旦这么说了,就必须这么做!):
         java中有一条这样的规则:
             方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法!)
         java中还有一条语法规则:
             return语句一旦执行,整个方法必须结束(亘古不变的语法!)

运行结果

 可以看出,虽然finally语句块执行了,但是,return的值还是100!!
     为什么?看看反编译的结果
             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(){
 ​
     }
 }
 ​

自定义的异常类

 Java中怎么自定义异常呢?
     两步:
         "第一步:编写一个类继承Exception或者RuntimeException.
         "第二步:提供两个构造方法,一个无参数的,一个带有String参数的。

实例

 public class MyException extends Exception{ // 编译时异常
     public MyException(){
 ​
     }
     public MyException(String s){
         super(s);
     }
 }

异常的综合实例

     编写程序,使用一维数组,模拟栈数据结构。
     要求:
         1、这个栈可以存储java中的任何引用类型的数据。
         2、在栈中提供push方法模拟压栈。(栈满了,要有提示信息。)
         3、在栈中提供pop方法模拟弹栈。(栈空了,也有有提示信息。)
         4、编写测试程序,new栈对象,调用push pop方法来模拟压栈弹栈的动作。
         5、假设栈的默认初始化容量是10.(请注意无参数构造方法的编写方式。)

自定义异常方法

 public class StackException extends Exception{
     public StackException(){
 ​
     }
     public StackException(String s){
         super(s);
     }
 }
 ​

测试类

 import java.util.ArrayList;
 import java.util.List;
 ​
 public class Test {
     static int temp = 0;
     public static void main(String[] args) {
 //        创建一个集合对象并指定其初始容量
         List<Object> mylist = new ArrayList<Object>(10);//自定义栈的初始容量为10
 //        创建一个本类的对象,方便来调用下面的实例方法
         Test test = new Test();
 //        模拟压栈
         test.push(mylist,1);
         test.push(mylist,2);
         test.push(mylist,3);
         test.push(mylist,4);
 ​
 //        模拟弹栈
         test.pop(mylist);
         test.pop(mylist);
         test.pop(mylist);
         test.pop(mylist);
 ​
     }
 ​
 ​
 //压栈方法
     public void push(List list,Object object){
         if(temp <= 9){
             list.add(temp,object);
             System.out.println("添加元素"+object+"成功!");
             temp++;
         }else{
             try {
                 throw new StackException("添加元素"+object+"失败,栈已满!!!");
             } catch (StackException e) {
                 e.printStackTrace();
             }
         }
 ​
     }
 //    弹栈方法
 ​
 ​
     public void pop (List list){
         if(temp > 0){
             Object o1 = list.get(temp-1);
             list.remove(temp-1);
             System.out.println("删除元素"+o1+"成功!!!");
             temp--;
         }else{
             try {
                 throw new StackException("弹栈失败,栈已空!!!");
             } catch (StackException e) {
                 e.printStackTrace();
             }
         }
     }
 }
 ​