• JAVA基础-异常


    1. 异常的概念

    在Java中异常被当做对象来处理,根类是java.lang.Throwable类。所有异常类分为两大类:Error和Exception

    • Error是无法处理的异常,比如OutOfMemoryError(内存),一般发生这种异

    常,JVM会选择终止程序。因此我们编写程序时不需要关心这类异常

    • Exception,也就是我们经常见到的一些异常情况,这些异常是我们可以处理的

    2. 常见的异常及捕获

    下表中列出了几个常见的异常,其中所有的异常都是Exception的子类:

    我们使用try catch块来捕获异常,最基本的用法如下,我们捕获一个NullPointerException异常:

    Ps:请留意异常的打印到栈的用法。

    public class Ex1 {
    
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		try {
    			/*
    			 *  1.抛出到main的外面
    			 *  2.捕获
    			*/
    //			int a = 10/0;
    			String string = null;
    			System.out.println(string.length());
    			System.out.println("不报错");
    		} catch (Exception e) {
    			// TODO: handle exception
    			//异常的打印到栈
    			e.printStackTrace();
    			System.out.println("报错了");
    		}
    		
    		System.out.println("程序结束!!");
    	}
    
    }
    
    //输出:
    //java.lang.NullPointerException
    //报错了
    //程序结束!!
    //	at Ex1.main(Ex1.java:15)
    
    

    我们还可以捕获一个日期类型的异常:

    这里我们顺便复习了如何用Date类去统计某一段程序的运行时间。

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Ex2 {
    
    	
    	public static void main(String[] args)  {
    		
    		//统计运行时间
    		Date d1=new Date();
    		System.out.println(d1);
    		long t1 = d1.getTime();
    		for(int i = 0;i < 100000000 ;i++) {
    			int a = i;
    			for(int j = 0;j < 100000000 ;j++) {
    				int b = 1;
    			}
    		}
    		Date d2 = new Date();
    		long t2 = d2.getTime();
    		System.out.println(t2-t1);
            
            //异常
    		SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
    		try {
    			Date d3 = s.parse("2020-12-aaaaaaa");
    			System.out.println(s.format(d3));
    			System.out.println("okokoko");
    		} catch (ParseException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    }
    
    
    /*
    Sun Apr 12 22:19:29 CST 2020
    78
    java.text.ParseException: Unparseable date: "2020-12-aaaaaaa"
    at java.base/java.text.DateFormat.parse(Unknown Source)
    at Ex2.main(Ex2.java:26)
     * */
     */
    

    上面这段程序的异常类型是ParseException类型,我们可以从parse函数的源码中知道为什么。

        public Date parse(String source) throws ParseException
        {
            ParsePosition pos = new ParsePosition(0);
            Date result = parse(source, pos);
            if (pos.index == 0)
                throw new ParseException("Unparseable date: "" + source + """ ,
                    pos.errorIndex);
            return result;
        }
    

    下面我们捕获一个ClassCastException异常;

    public class Man {
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		try {
                //向上转换
    			Man m1 = new Teacher();
    			Student s1 = (Student)m1;
    		} catch (Exception e) {
    			// TODO: handle exception
    			e.printStackTrace();
    		}
    		System.out.println("运行结束");
    	}
    }
    
    /*
    java.lang.ClassCastException: Teacher cannot be cast to Student
    运行结束
    	at Man.main(Man.java:12)
    */
    
    public class Student extends  Man{
    
    }
    
    public class Teacher extends Man{
    
    }
    

    下面是一个ArrayIndexOutOfBoundsException异常,同样的还有字符串对应的IndexOutOfBoundsException(不演示了);

    public class Ex3 {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    
    		try {
    			int[] num = new int[3];
    			num[4] = 2; 
    		} catch (Exception e) {
    			// TODO: handle exception
    			e.printStackTrace();
    		}
    	}
    
    }
    
    //
    //java.lang.ArrayIndexOutOfBoundsException: 4
    //at Ex3.main(Ex3.java:9)
    

    下面捕获一个输入异常InputMismatchException,如果我们输入了一个字符串,基本的情况如下;

    import java.util.Scanner;
    
    public class Ex4 {
    	
    	public int getInputNum() {
    		Scanner s = new Scanner(System.in);
    		return s.nextInt();
    	}
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		Ex4 ex4 = new Ex4();
    		
    		System.out.println(ex4.getInputNum());
    
    	}
    
    }
    /**
    Exception in thread "main" java.util.InputMismatchException
    	at java.base/java.util.Scanner.throwFor(Unknown Source)
    	at java.base/java.util.Scanner.next(Unknown Source)
    	at java.base/java.util.Scanner.nextInt(Unknown Source)
    	at java.base/java.util.Scanner.nextInt(Unknown Source)
    	at Ex4.getInputNum(Ex4.java:7)
    	at Ex4.main(Ex4.java:14)
    */
    

    我们想要让这段代码具有更高的容错率,如果我们输入了字符串或其他,应该让我们重复输入,直到我们输入了正确的int类型:

    import java.util.Scanner;
    
    public class Ex4 {
    	
    	public int getInputNum() {
    		while (true) {
    			try {
    				System.out.println("请输入数字:");
    				Scanner s = new Scanner(System.in);
    				return s.nextInt();
    			} catch (Exception e) {
    				// TODO: handle exception
    				System.out.println("您的输入不是数字");
    			}
    		}
    	}
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Ex4 ex4 = new Ex4();
    		System.out.println(ex4.getInputNum());
    	}
    
    }
    
    /**
    请输入数字:
    sen
    您的输入不是数字
    请输入数字:
    12
    12
    
    */
    

    3. 异常的抛出

    异常可以大致分为两类:编译时异常(显式异常)和运行时异常(隐式异常)

    首先我们来看一个显式异常的例子:

    这里的parseException是一个显式异常,必须在编译期处理,类似的还有SQLException和IOException

    我们对于这种异常,必须在编写程序的时候添加抛出(throws ParseException),不然编译器就会爆红;

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Ex5 {
    
    	public Date getDate(String sDate) throws ParseException {
    		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    		return simpleDateFormat.parse(sDate);
    	}
    	
    	//parseException 显式异常,必须在编译期处理
    	//类似的还有SQLException和IOException
    	public static void main(String[] args) {
    		
    		Ex5 ex5 = new Ex5();
    		try {
    			System.out.println(ex5.getDate("2020-1-3"));
    		} catch (ParseException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		
    	}
    }
    
    

    下面再来看一个隐式异常:

    这里如果分母是0的话会出现异常,这种异常在编译期间是不处理的,编译期间不报错,如果不处理,一旦发生异常,就会造成程序的终止。

    public class Ex6 {
    
    	public int math(int a,int b) {
    		return a/b;
    	}
        
    	/**
    	 * 隐式异常(运行时异常)的处理
    	 * 这种异常在编译期间是不处理的,编译期间不报错;
    	 * 如果不处理,一旦发生异常,就会造成程序的终止
    	 */
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Ex6 ex6 = new Ex6();
    		ex6.math(10, 0);
    		System.out.println("all is ok");
    	}
    }
    
    /**
    Exception in thread "main" java.lang.ArithmeticException: / by zero
    	at Ex6.math(Ex6.java:6)
    	at Ex6.main(Ex6.java:17)
    	*/
    

    在处理异常的时候我们有两个关键字 throws和throw

    throws的用法就是在函数的方法名后面可以抛出异常,throw可以用来转换异常。

    我们可以看出throw是动词,所以是一个转换的动作。

    注意,异常的抛出和截获要保持一致。

    这里利用throw把ParseException转换成IOException。(并没有什么用,仅仅为了演示用法)

    import java.io.IOException;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import javax.imageio.IIOException;
    
    public class Ex5 {
    	
    	public Date getDate(String sDate) throws IOException  {
    		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    		
    		try {
    			return simpleDateFormat.parse(sDate);
    		} catch (ParseException e) {
    			//利用throw把ParseException转换成IOException
                //同时,throws对应的异常也要改。
    			throw new IOException();
    		}
    	}
    	
    	//parseException 显式异常,必须在编译期处理
    	//类似的还有SQLException和IOException
    	public static void main(String[] args) {
    		
    		Ex5 ex5 = new Ex5();
    		try {
    			System.out.println(ex5.getDate("AAA-1-3"));
                //异常的抛出和截获要保持一致。
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		
    	}
    }
    /**
    java.io.IOException
    at Ex5.getDate(Ex5.java:18)
    at Ex5.main(Ex5.java:28)
    */
    
    

    4. 自定义异常

    我门可以通过继承Exception来自定义异常,自定义异常实际上是实际上用的最多的地方。

    我门假设以下情况:

    1586761528379

    这里我们主要模拟这里的用户异常和系统异常。

    首先先创建系统异常和用户异常两个异常类,继承与Exception。

    package demo2;
    
    //自定义异常--用户级异常
    public class appException extends Exception{
    
    	//	异常码和异常信息
    	private int ErrorCode;
    	private String ErrMessags;
    	
    	/**
    	 * 有参数的构造器
    	 * @param errorCode
    	 * @param errMessags
    	 */
    	public appException(int errorCode, String errMessags) {
    		super();
    		ErrorCode = errorCode;
    		ErrMessags = errMessags;
    	}
    	
    	public int getErrorCode() {
    		return ErrorCode;
    	}
    	public void setErrorCode(int errorCode) {
    		ErrorCode = errorCode;
    	}
    	public String getErrMessags() {
    		return ErrMessags;
    	}
    	public void setErrMessags(String errMessags) {
    		ErrMessags = errMessags;
    	}
    }
    
    
    package demo2;
    
    
    //自定义异常--系统级异常
    public class systemException extends Exception{
    	//	异常码和异常信息
    	private int ErrorCode;
    	private String ErrMessags;
    	
    	/**
    	 * 有参数的构造器
    	 * @param errorCode
    	 * @param errMessags
    	 */
    	public systemException(int errorCode, String errMessags) {
    		super();
    		ErrorCode = errorCode;
    		ErrMessags = errMessags;
    	}
    
    	public int getErrorCode() {
    		return ErrorCode;
    	}
    	public void setErrorCode(int errorCode) {
    		ErrorCode = errorCode;
    	}
    	public String getErrMessags() {
    		return ErrMessags;
    	}
    	public void setErrMessags(String errMessags) {
    		ErrMessags = errMessags;
    	}
    }
    
    

    随后我们模拟上图中的两种异常:

    建立主函数来调用我们创建好的两个异常:

    package demo2;
    
    public class Ex8 {
    
    	public int math(int a,int b) throws appException, systemException {
    		try {
    //			数组越界异常,利用系统异常抛出
    			int[] nums = new int[3];
    			nums[3] = 8;
    //			数学运算异常,利用用户异常抛出
    			return a/b;
    		} catch (ArithmeticException e) {
    			//转换成自定义异常为用户级异常;
    			throw new appException(1001, "b不能为0!");
    		}catch (IndexOutOfBoundsException e) {
    			// TODO: handle exception
    			throw new systemException(999, "系统异常!");
    		}
    		
    	}
    	public static void main(String[] args) {
    		Ex8 ex8 = new Ex8();
    		
    		try {
    			ex8.math(20, 0);
    		} catch (appException e) {
    			System.out.println(e.getErrMessags());
    		}catch (systemException e) {
    			System.out.println(e.getErrMessags());
    		}
    		System.out.println("finished!");
    	}
    }
    
    //系统异常!
    //finished!
    
    
    
  • 相关阅读:
    SPRING IN ACTION 第4版笔记-第五章BUILDING SPRING WEB APPLICATIONS-006-处理表单数据(注册、显示用户资料)
    SPRING IN ACTION 第4版笔记-第五章BUILDING SPRING WEB APPLICATIONS-005-以path parameters的形式给action传参数(value=“{}”、@PathVariable)
    SPRING IN ACTION 第4版笔记-第五章BUILDING SPRING WEB APPLICATIONS-004-以query parameters的形式给action传参数(@RequestParam、defaultValue)
    用CALayer实现聚光灯效果
    用CALayer实现淡入淡出的切换图片效果
    使用CAEmitterLayer实现下雪效果
    使用CAEmitterLayer产生粒子效果
    xcode 删除 Provisioning Profile
    git add相关
    接入淘宝SDK(OneSDK)和支付宝SDK(AlipaySDK)出现 duplicate symbols for architecture i386
  • 原文地址:https://www.cnblogs.com/JeasonIsCoding/p/13232538.html
Copyright © 2020-2023  润新知