课后作业——2022.10.15

1.动手动脑:

请阅读并运行AboutException.java示例,然后通过后面的几页PPT了解Java中实现异常处理的基础知识。

import javax.swing.*;
 
class AboutException {
   public static void main(String[] a) 
   {
      int i=1, j=0, k;
      k=i/j;
 
 
    try
    {
         
        k = i/j;    //Causes division-by-zero exception
        throw new Exception("Hello.Exception!");
    }
     
    catch ( ArithmeticException e)
    {
        System.out.println("被0除.  "+ e.getMessage());
    }
     
    catch (Exception e)
    {
        if (e instanceof ArithmeticException)
            System.out.println("被0除");
        else
        {  
            System.out.println(e.getMessage());
             
        }
    }
 
     
    finally
     {
            JOptionPane.showConfirmDialog(null,"OK "+k);
     }
         
  }
 
}

结果:

结论:

把可能会发生错误的代码放进try语句块中。
当程序检测到出现了一个错误时会抛出一个异常对象。异常处理代码会捕获并处理这个错误。
catch语句块中的代码用于处理错误。
当异常发生时,程序控制流程由try语句块跳转到catch语句块。
不管是否有异常发生,finally语句块中的语句始终保证被执行。
如果没有提供合适的异常处理代码,JVM将会结束掉整个应用程序。

Throwable类有两个直接子类:

  Exception:出现的问题是可以被捕获的;

  Error:系统错误,通常由JVM处理。

2.请尝试解释以下奇怪的现象

结论:

(1)的代码运行时会引发异常,而(2)的代码不会引发异常!为什么?

对于(1)而言,java生成的是idiv字节码指令,而(2)java生成的是ddiv字节码指令,

JVM在具体实现这两个指令是,采用了不同的处理策略,导致两段代码运行时得到不同的结果

 3.动手动脑:多层的异常捕获

阅读以下代码(CatchWho.java),写出程序运行结果:

代码:

public class CatchWho { 
    public static void main(String[] args) { 
        try { 
                try { 
                    throw new ArrayIndexOutOfBoundsException(); 
                } 
                catch(ArrayIndexOutOfBoundsException e) { 
                    System.out.println(  "ArrayIndexOutOfBoundsException" +  "/内层try-catch"); 
                }
  
            throw new ArithmeticException(); 
        } 
        catch(ArithmeticException e) { 
            System.out.println("发生ArithmeticException"); 
        } 
        catch(ArrayIndexOutOfBoundsException e) { 
           System.out.println(  "ArrayIndexOutOfBoundsException" + "/外层try-catch"); 
        } 
    } 
}

结果:

写出CatchWho2.java程序运行的结果:

代码:

public class CatchWho2 {
    public static void main(String[] args) {
        try {
                try {
                    throw new ArrayIndexOutOfBoundsException();
                }
                catch(ArithmeticException e) {
                    System.out.println( "ArrayIndexOutOfBoundsException" + "/内层try-catch");
                }
            throw new ArithmeticException();
        }
        catch(ArithmeticException e) {
            System.out.println("发生ArithmeticException");
        }
        catch(ArrayIndexOutOfBoundsException e) {
            System.out.println( "ArrayIndexOutOfBoundsException" + "/外层try-catch");
        }
    }
}

结果:

throw一个异常后,必须catch成功,才能throw下一个异常,系统不能累积处理异常

4.动手动脑:

当有多个嵌套的try…catch…finally时,要特别注意finally的执行时机。
请先阅读 EmbedFinally.java示例,再运行它,观察其输出并进行总结。

代码:

public class EmbededFinally {
 
     
    public static void main(String args[]) {
         
        int result;
         
        try {
             
            System.out.println("in Level 1");
 
            
            try {
                 
                System.out.println("in Level 2");
  // result=100/0;  //Level 2
                
                try {
                    
                    System.out.println("in Level 3");
                       
                    result=100/0;  //Level 3
                 
                }
                 
                catch (Exception e) {
                     
                    System.out.println("Level 3:" + e.getClass().toString());
                 
                }
                 
                 
                finally {
                     
                    System.out.println("In Level 3 finally");
                 
                }
                 
                
                // result=100/0;  //Level 2
 
             
                }
             
            catch (Exception e) {
                
                System.out.println("Level 2:" + e.getClass().toString());
            
            }
            finally {
                 
                System.out.println("In Level 2 finally");
            
             }
              
            // result = 100 / 0;  //level 1
         
        }
         
        catch (Exception e) {
             
            System.out.println("Level 1:" + e.getClass().toString());
         
        }
         
        finally {
            
            System.out.println("In Level 1 finally");
         
        }
     
    }
 
}

结果:

当有多层嵌套的finally时,异常在不同的层次抛出 ,在不同的位置抛出,可能会导致不同的finally语句块执行顺序。

5.动手动脑:

finally语句块一定会执行吗?
请通过 SystemExitAndFinally.java示例程序回答上述问题

代码:

public class SystemExitAndFinally {
 
     
    public static void main(String[] args)
    {
         
        try{
 
             
            System.out.println("in main");
             
            throw new Exception("Exception is thrown in main");
 
                    //System.exit(0);
 
         
        }
         
        catch(Exception e)
 
            {
             
            System.out.println(e.getMessage());
             
            System.exit(0);
         
        }
         
        finally
         
        {
             
            System.out.println("in finally");
         
        }
     
    }
 
 
}

结果:

 

 

不一定,因为当代码 System.exit(0);意思是,终止JAVA虚拟机,导致不能执行finally的内容!

6.请通过 PrintExpressionStack.java示例掌握上述内容。依据对本讲多个示例程序的分析,请自行归纳总结出Java多层嵌套异常处理的基本流程。

代码:

// UsingExceptions.java

// Demonstrating the getMessage and printStackTrace

// methods inherited into all exception classes.

public class PrintExceptionStack {

   public static void main( String args[] )

   {

      try {

         method1();

      }

      catch ( Exception e ) {

         System.err.println( e.getMessage() + "\n" );

         e.printStackTrace();

      }

   }

   public static void method1() throws Exception

   {

      method2();

   }

   public static void method2() throws Exception

   {

      method3();

   }

   public static void method3() throws Exception

   {

      throw new Exception( "Exception thrown in method3" );

   }

}

结果:

7.

请看以下代码,它们完全符合Java语法规范,但事实是它们不能通过编译:
public class TestThrows {
public static void main(String[] args) {
FileInputStream fis = new
FileInputStream("a.txt");
}
}

结果:

throws语句表明某方法中可能出现某种(或多种)异常,但它自己不能处理这些异常,而需要由调用者来处理。
当一个方法包含throws子句时,需要在调用此方法的代码中使用try/catch/finally进行捕获,或者是重新对其进行声明,否则编译时报错。

throws语句中声明的异常称为受控(checked)的异常,通常直接派生自Exception类。
RuntimeException(其基类为Exception) 和Error(基类为Throwable)称为非受控的异常。这种异常不用在throws语句中声明。
CheckedExceptionDemo.java示例展示了上述两种异常的特性。

8.抛出多个受控异常的方法
一个方法可以声明抛出多个异常
    int g(float h) throws OneException,TwoException
        { …… }
ThrowMultiExceptionsDemo.java示例展示了相关特性。
注意一个Java异常处理中的一个比较独特的地方:

 

 

import java.io.*;
public class ThrowMultiExceptionsDemo { 
    public static void main(String[] args) 
        { 
      try { 
            throwsTest(); 
       } 
        catch(IOException e) { 
            System.out.println("捕捉异常"); 
        }
    }

    private static void throwsTest()  throws ArithmeticException,IOException { 
        System.out.println("这只是一个测试"); 
        // 程序处理过程假设发生异常
        throw new IOException(); 
        //throw new ArithmeticException(); 
    } 
}

结果:

9.

一个子类的throws子句抛出的异常,不能是其基类同名方法抛出的异常对象的父类。
OverrideThrows.java示例展示了Java的这个语法特性。

代码:

import java.io.*;


public class OverrideThrows
{
    public void test()throws IOException
    {
        FileInputStream fis = new FileInputStream("a.txt");
    }
}
class Sub extends OverrideThrows
{
    //如果test方法声明抛出了比父类方法更大的异常,比如Exception
    //则代码将无法编译……
    public void test() throws FileNotFoundException
    {
            //...
    }
}

10.在实际开发中,经常需要将特定的“过于专业”的异常转换为一个“业务”异常,然后在调用者处进行捕获与处理。

ExceptionLinkInRealWorld.java示例展示了典型的异常处理代码模板

代码:

/**
 * 自定义的异常类
 * @author JinXuLiang
 *
 */
class MyException extends Exception
{
    public MyException(String Message) {
        super(Message);
    }
    public MyException(String message, Throwable cause) {
        super(message, cause);
    }
     public MyException( Throwable cause) {
        super(cause);
    }

}

public class ExceptionLinkInRealWorld {
   public static void main( String args[] )
   {
      try {
         throwExceptionMethod();  //有可能抛出异常的方法调用
      }
      catch ( MyException e )
      {
         System.err.println( e.getMessage() );
         System.err.println(e.getCause().getMessage());
      }
      catch ( Exception e )
      {
         System.err.println( "Exception handled in main" );
      }
      doesNotThrowException(); //不抛出异常的方法调用
   }

   public static void throwExceptionMethod() throws MyException
   {
      
      try {
         System.out.println( "Method throwException" );

         throw new Exception("系统运行时引发的特定的异常");  // 产生了一个特定的异常
      }
      catch( Exception e )
      {
         System.err.println(
            "Exception handled in method throwException" );
         //转换为一个自定义异常,再抛出
         throw new MyException("在方法执行时出现异常",e);

         
      }
      finally {
         System.err.println(
            "Finally executed in throwException" );
      }

      // any code here would not be reached
   }

   public static void doesNotThrowException()
   {
      try {
         System.out.println( "Method doesNotThrowException" );
      }
      catch( Exception e )
      {
         System.err.println( e.toString() );
      }
      finally {
         System.err.println(
            "Finally executed in doesNotThrowException" );
      }

      System.out.println(
         "End of method doesNotThrowException" );
   }
}

结果:

 

 在实际开发中,可以参照ExceptionLinkInRealWorld.java
 示例的做法,定义一些与业务逻辑相关的自定义异常类,供上层代码进行捕获,从而能更精确地反映系统真实运行情况并及时进行处理。

posted @ 2022-10-15 22:45  sodamate  阅读(25)  评论(0编辑  收藏  举报