• 异常处理


    20145217 《Java程序设计》第5周学习总结(1)

    教材学习内容总结

    程序中总有一些意想不到的状况所引发的错误,我们都知道Java是面向对象的编程,Java中的错误也已对象的方式呈现为java.lang.Throwable的各种子类。第八章内容主要讲述的是Java中对异常情况的处理方法。

    8.1trycatch语法

    Java中所有错误都会包装为对象,如果你愿意,可以尝试try执行程序并捕捉catch代表错误的对象后做一些处理。使用了trycatch语法,Jvm会尝试执行try区块中的程序代码,如果发生错误,执行流程会跳离错误发生点,然后比对catch括号声明的类型,是否符号被抛出的错误对象类型,若果是的话,就执行catch区块中的程序代码。

    对于求几个数平均数的程序Average.java

    package cc.openhome;
    import java.util.Scanner;
    public class Average {
    	public static void main(String[] args) {
    		Scanner console=new Scanner(System.in);
    		double sum=0;
    		int count=0;
    		while (true){
    			double number = console.nextDouble();
    			if (number==0) 
    			break;
    			sum += number;
    			count++;   
    			}
    		System.out.printf("平均%.2f%n",sum/count);
    	}  
    }
    

    如果过用户正确输入数据,就会产生正确结果。但如果用户一不小心输入错误,就会出现错误信息:


    InputMismatchException表示不符合Scanner对象预期,因为Scanner对象预期下一个字符串本身要代表数字。正像前文所说的,Java中所有的错误都会被打包对象,这时候可以尝试try捕捉catch代表错误的对象进行一些处理。即将代码中对应文段改为:

    try{
    	Scanner console=new Scanner(System.in);
    	double sum=0;
    	int count=0;
    	while (true){
    		double number = console.nextDouble();
    		if (number==0) 
    		break;
    		sum += number;
    		count++; 
    		}
    	System.out.printf("平均%.2f%n",sum/count);
    }catch(InputMismatchException ex){
    	System.out.println("必须是数字");
    }
    

    这时当输入错误信息时会出现:


    当然也可以在产生错误时更友好的显示错误,将代码段修改为

    while (true){
    	try{
    		double number = console.nextDouble();
    		if (number==0) 
    		break;
    		sum += number;
    		count++;   
    	}catch(InputMismatchException ex){
    		System.out.printf("略过非数字输入%s%n",console.next());
    	}
    }
    

    输入同样信息,输出结果为:


    8.2异常继承结构

    当程序设计本身出了错误,此时建议使用Exception或其子类实例来表现,所以通常称错误处理为异常处理。

    • 运行时异常都是RuntimeException类及其子类异常,如NullPointerExceptionIndexOutOfBoundsException等, 这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的, 程序应该从逻辑角度尽可能避免这类异常的发生。 非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。 从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。 如IOExceptionSQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
    • errorexceptionThrowable的唯二子类。error表示恢复不是不可能但很困难的情况下的一种严重问题,比如说内存溢出,不可能指望程序能处理这样的情况。 exception表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。
    • 使用trycatch捕捉对象时也要注意,如果父类异常对象在子类异常对象前被捕捉,则catch子类对象的区块将永远不会被执行,编译程序会检查出错。

    Java是唯一采用受检异常的语言,这有两个目的:一是文件化,二是提供编译程序信息。

    8.3throws用法

    如果设计流程中发生异常,而设计时并没有充足的信息知道该如何处理,那么可以抛出异常,让调用方法的客户端来解决。为了告诉编译程序这个事实,必须使用 throws声明此方法会抛出的异常类型或父类型,才会通过编译。在流程中抛出异常,就直接跳离原有流程,可以抛出受检或非受检异常。若果抛出受检异常则表示认为客户端有能力且应处理异常,此时必须要throws声明;若果抛出非受检异常则表示认为客户端调用方法时机出错,抛出异常要求是要求客户端修正这个漏洞再来调用方法 ,此事也就不用throws声明。

    • throws是用来声明一个方法可能抛出的所有异常信息;throw则是指抛出的一个具体的异常类型。
    • 通常在一个方法(类)的声明处通过throws声明方法(类)可能抛出的异常信息,而在方法(类)内部通过throw声明一个具体的异常信息。
    • throws通常不用显示的捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法;throw则需要用户自己捕获相关的异常,而后在对其进行相关包装,最后在将包装后的异常信息抛出。

    8.4堆栈追踪

    再多重方法调用下,异常发生点可能是在某个方法之中,若想要得知异常发生的根源,以及多重方法调用下异常的堆栈传播,可以利用异常对象自动收集的堆栈追踪来获得相关信息,StackTraceDemo.java

    package cc.openhome;
    public class StackTraceDemo {
    	public static void main(String[] args) {
        	try{
            	c();
        	}catch (NullPointerException ex){
            	ex.printStackTrace();
        	}
    	}
    	static void c(){
        	b();
    	}
    	static void b(){
        	a();
    	}
    	static String a(){
        	String text = null;
        	return text.toUpperCase();
    		}  
    }
    

    printStackTrace()在控制台显示显示堆栈追踪:


    如果要取得个别的堆栈元素进行处理,则可以使用getStackTrace(),这会返回StackTraceElenment数组。
    要善用堆栈追踪的前提是代码中不能有私吞异常行为,例如在捕捉异常后什么都不做:

    try{
    	···
    }catch(FileNotFoundException ex){}
    

    如果要让堆栈起点成为重抛异常的地方,可以使用fillInStackTrace()方法,这个方法会重新装填堆栈,将起点设为重抛异常的地方,返回Throwable对象。StackTraceDemo3.java:

    package cc.openhome;
    public class StackTraceDemo3 {
        public static void main(String[] args) {
            try{
                c();
            }catch (NullPointerException ex){
                ex.printStackTrace();
            }
        }
        static void c(){
            try{
                b();
            }catch(NullPointerException ex){
                ex.printStackTrace();
                Throwable t=ex.fillInStackTrace();
                throw (NullPointerException)t;
        }
        }
        static void b(){
                 a();
        }
        static String a(){
            String text = null;
            return text.toUpperCase();
        }
    }
    

    显示结果为:


    8.5关于assert

    断言结果一定是成立或者不成立,预期结果与实验结果相同,断言成立否则不成立。使用断言:

    • 断言客户端调用程序方法前,已经准备好某些前置条件。
    • 断言客户端调用程序方法后,具有方法承诺的结果。
    • 断言对象某个时间点下的状态。
    • 使用断言取代批注。
    • 断言程序流程中绝对不会执行到的程序代码部分。

    8.6使用finally

    trycatch语法还可以搭配finally,无论程序是因为异常而中止或其它方式返回终止的,都会执行finally区块。FinallyDemo.java

    package cc.openhome;
    public class Finallydemo {
        public static void main(String[] args) {
            System.out.println(test(true));
        }
        public static int test(boolean flag){
            try{
                if(flag){
                    return 1;
                }
            }finally{
                        System.out.println("finally···");
                        }
                return 0;
        }   
    }
    

    结果为:


    可见函数会将finally块会先执行完,再将值返回。

    8.7尝试关闭资源语法

    尝试关闭资源语法可套用的对象,必须操作java.lang.AutoCloseable接口。AutoCloseDemo.java

    package cc.openhome;
    public class AutoClosableDemo {
        public static void main(String[] args) {
            try(Resource res=new Resource()){
                res.doSome();
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }
        
    }
    class Resource implements AutoCloseable{
        void doSome(){
            System.out.println("做一些事");
        }
        @Override
        public void close()throws Exception{
            System.out.println("资源被关闭");
        }
    }
    

    结果为:


    尝试关闭资源语法也可以同时关闭两个以上的对象资源,中间要用分号隔开。AutoCloseDemo2.java

    package autoclosabledemo2;
    public class AutoClosableDemo2 {
        public static void main(String[] args) {
            try(ResourceSome some=new ResourceSome();
                    ResourceOther other =new ResourceOther()){
                some.doSome();
                other.doOther();
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }   
    }
    class ResourceSome implements AutoCloseable{
        void doSome(){
            System.out.println("做一些事");
        }
        @Override
        public void close()throws Exception{
            System.out.println("资源Some被关闭");
        }
    }
     class ResourceOther implements AutoCloseable{
        void doOther(){
            System.out.println("做其他事");
        }
        @Override
        public void close()throws Exception{
            System.out.println("资源Other被关闭");
        }
    }  
    

    运行结果为:


    在try括号中,越后面撰写的对象资源会越早被关闭。

    教材学习中的问题和解决过程

    教材中很多地方讲解不详细,我参考了网上大量的资料,才初有体会,如网名为Glory的一片博客(http://www.cnblogs.com/ggzss/archive/2011/08/18/2145017.html):


    代码调试中的问题和解决过程

    代码遇到了不小的问题,有点看不大懂了呢,于是便在小组中发了帖子:


    上传代码到git:


    学习进度条

    代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
    目标 5000行 30篇 400小时
    第三周 300/600 2/6 20/50
    第四周 300/900 2/8 16/66
    第五周 100/1200 1/10 8/82

    参考资料

  • 相关阅读:
    重载小于号
    无聊的会议
    程序内存和时间
    对拍
    读入和输出优化
    codevs 3269 混合背包
    清北第三套题
    codevs 2188 最长上升子序列
    清北第二套题
    [COGS896] 圈奶牛
  • 原文地址:https://www.cnblogs.com/jokebright/p/5349860.html
Copyright © 2020-2023  润新知