【Java21】异常,finally

文章目录


1.错误和异常区别:Arrays.toString(array)

package com.itheima01.throwable;
import java.util.Arrays;
//错误(Error) : 从程序角度 只能避开,不能解决。 异常(Exception) : 从程序角度 可以解决的问题
public class ThrowableDemo {
    public static void main(String[] args) {   
        // int[] array = new int[3];
        //System.out.println(array); //[I@6d6f6e28
        //System.out.println(array.toString()); //[I@6d6f6e28
        //System.out.println(Arrays.toString(array)); //[0, 0, 0]   

// int[] array = new int[2_000_000_000]; //20亿撑不住,内存条不够
// System.out.println(Arrays.toString(array)); //java.lang.OutOfMemoryError: Java heap(堆) space //OOM :内存溢出【错误】
        int[] array = {};
        System.out.println(array[1]); //java.lang.ArrayIndexOutOfBoundsException【异常】
    }
}

【Java21】异常,finally

package com.itheima02.jvm;
import java.util.ArrayList;
/*
*  throw 关键字(全小写): 1. 效果等同于return,后续代码不再执行
*       2. throw + Throwable对象(只能跟异常对象);  return 返回值;
*       3. 运用: 我们一般不使用, JDK方法的设计者 (抛出异常: api设计者 和 使用者交流方式)
*/
public class ThrowDemo {
    public static void main(String[] args) {
//        new ArrayList<String>(-1); //IllegalArgumentException
        int[] array = {0,1};
        int element = getElement(array);
        System.out.println(element);
    }

    private static int getElement(int[] array) {
        int index = 2;
        if(index > array.length - 1){ //>2-1
            //访问了数组不存在的索引
//          ArrayIndexOutOfBoundsException e = new ArrayIndexOutOfBoundsException("you are a stupid bird,you access a wrong index:" + index);
//          throw e; //抛出异常,下面代码不会执行。抛出去之后也没人处理	
		
            throw  new ArrayIndexOutOfBoundsException(index); //这一行等同上两行            
			//throw new Throwable(""); //也可以,因为是编译异常,声明getElement方法后要加throws Throwable
        }
        int element = array[index]; //上面有throw,这里两行都不执行
        return element;
    }
}

2.编译和运行异常:SimpleDateFormat

【Java21】异常,finally

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        String str = "1996-01-01";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(sdf); //java.text.SimpleDateFormat@f67a0200
        
//  sdf.parse(str); //解析异常ParseException也叫编译异常,和IOException并列关系,main声明需抛出。
        Date parse = sdf.parse(str); //加上Date parse不报错
        System.out.println(parse); //Mon Jan 01 00:00:00 CST 1996

//   FileOutputStream fos = new FileOutputStream(""); //FileNotFoundException是IOException子类
//   fos.write(97); //IOException是最经典的编译异常

//111111111111111111111111111111111111111111111以下都为RuntimeException的子类
//       1.  NullPointerException  空指针
        String s = null;
//        System.out.println(s.length());

// 		2. IndexOutOfBoundsException  索引越界
        int[] array = {};
//        System.out.println(array[1]);

        // 3. ClassCastException  类转换
        // 4. IllegalArgumentException 非法参数
        new ArrayList<String>(-1);
    }
}

3.处理异常:方法声明抛出

【Java21】异常,finally

package com.itheima03.throwsd;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class ThrowsDemo {
    public static void main(String[] args) throws IOException {
        method01(); //表哥又抛出去叫大哥(jvm,因为main方法调用者是jvm),jvm出错又打印终止
    } 
    /*
    *  throws 关键字
    *    1. 用在方法声明上: 修饰符 返回值类型 方法名(参数列表) throws 异常类型(A)
    *    2. 这是处理异常的一种方式: 声明将异常抛出给调用者处理(假手与人)
    *    3. 注意: 这里的异常类型A 必须跟方法里要抛出的异常B一致, 或者A是B的父类 (向上转型)
    * 
    *    语法: throws 异常1,异常2{ }
    *    运用: 我们可以在某一方法的设计上先声明抛出异常,可以方法的调用处进行处理
    *         切记有有一环节必须处理, 不然到JVM中, 出现异常就崩溃
    *    我们平时学习为了省事, 如果明知不会错的异常,直接throws
    */
    private static void method01() throws IOException { //交给表哥 
        FileOutputStream fos = new FileOutputStream("a.txt");
        fos.write(97);
    }
}

【Java21】异常,finally

package com.itheima04.trycatch;

public class TrycatchDemo {
    public static void main(String[] args) {
        int[] array = {0,1};
        try{
            int element = array[2];
            System.out.println(element);
        }catch (Exception e){
            e.printStackTrace();//打印异常信息: 打印栈中追溯,案发地点在方法栈中。jvm不会打印了,我们自己手动打印。这行注释了,下面红字不会打印,但“出现异常..继续运行...”都会打印出。
            System.out.println("出现异常,并被捕获了");
        }
        System.out.println("程序继续执行");
    }
}

【Java21】异常,finally

package com.itheima04.trycatch;
import java.util.Scanner;
/*
*   try...catch运用: 1. 如果代码都是由我们自己编写的,我们一般都不会出现异常
*        2. 有些代码需要用户参与编写 (交互: 我们程序输出,用户输入)
*思想: 我们预知代码可能运行结果(如果了包含了异常, 提前try...cath并给出提示或者解决方案)
*/
public class TryCatchDemo02 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个被除数:");
        int a = sc.nextInt();
        
        System.out.println("请输入一个除数:");
        int b = sc.nextInt();        
        try {            
            int result = a/b; //java.lang.ArithmeticException: / by zero  算术异常
            System.out.println(result);
        }catch (Exception e){
            System.out.println("你个傻鸟,除数不能为0");
        }
        System.out.println("软件继续让你玩");
    }
}
package com.itheima04.trycatch;
/*
      try{
       }catch (NullPointerException e){
           //1. 如果出现了空指针,应该提示...
       }catch (IndexOutOfBoundsException e2){
           //2. 如果出现了索引越界, 应该提示...
       }
       思想: 异常的分类讨论
       执行顺序:
            如果try中代码发生异常, 那么多个catch会从上到下逐一尝试捕获,
            如果被A捕获了,后续的catch不再执行
       注意:
            1. 前面catch中的异常类型不能是后面catch中的异常类型的父类或者相同 (因为这样的话,后续catch执行不到没有意义)
            2. 后面catch中的异常类型可以是前面的父类
*/
public class TryCatchCatchDemo {
    public static void main(String[] args) {
       try{
           method01(2);
       }catch (NullPointerException e){
           System.out.println("发生了空指针异常");
       }catch (IndexOutOfBoundsException e2){
           System.out.println("发生了索引越界异常");
       }
        System.out.println("代码继续执行");
    }
    
    //模拟: 这段代码可能有两个异常(一段代码里面不论可能有多少个异常,一次运行最多抛出一个异常)
    private static void method01(int a) {
        if(a == 1){
            throw new NullPointerException("空指针"); //throw天生与其他代码互斥,一旦发生throw,其他代码不再运行
        }else if(a == 2){
            throw new IndexOutOfBoundsException("越界异常");
        }else{
            System.out.println("什么事都没发生");
        }
    }
}

【Java21】异常,finally

4.finally关键字:catch相当于else if,finally相当于else,return

package com.itheima04.trycatch;
/*
        try{
        }catch (Exception e){
        }finally {
           // 无论如何,一定最后执行。作用: (IO流)释放资源
        }
*/
public class FinallyDemo {
    public static void main(String[] args) {
//        method();
       int number =  method2();  //运行 :3
        System.out.println(number);  //1
    }	

//111111111111111111111111111111111111111111111111111111111111111111111 
    private static int method2() {
        int i = 1;
        try{
//          System.exit(0); //拔电源阻止finally
            return i;  
            //一般return后续代码不会执行了,但finally会抢夺try...catch中的return执行权
            //finally会先执行,执行完又回到return 
            //return 安全机制: 把i的值给记录下来了1 ,所以return 1 
        }catch (Exception e){ //没有异常,i永远不会=2
            i = 2;
        }finally {
            i = 3;
            System.out.println("运行 :" + i);
        }
        return i; //不执行,因为try catch finally有return了
    }

//11111111111111111111111111111111111111111111111111111111111111111111
    private static void method() {
        try{
            int i = 4/0;
            System.out.println(i);
        }catch (NullPointerException e){
            System.out.println("异常发生了");
        }finally {
            System.out.println("无论如何一定执行");
        }
        System.out.println("程序继续执行");
    }
}

【Java21】异常,finally
【Java21】异常,finally

5.自定义异常:extends

package com.itheima05.custom;
/*
*   JavaBean : 标准类 (封装)
*       1. private属性
*       2. public get set方法
*       3. public 空参构造,不声明构造会有一个空参构造。 写满参构造就得写空参构造。
* 
*   封装: 1. private属性 为了不对外直接暴露 -> 安全
*         2. public get set方法【方法跟属性最大不同, 方法可以加条件判断(健壮性校验)】
* 
*   继承: 自定义异常
*/
public class Student {
    private String name;
    private int age;
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        if(age < 0){
//            throw new IllegalArgumentException("你个傻鸟,age没有负数");
            throw new NoAgeException("你个傻鸟,age没有负数"); //不报错,因为下面class NoAgeException extends 。。。
        }
        this.age = age;
    }
}
package com.itheima05.custom;
/*
* 自定义异常: IllegalArgumentException : 非法参数异常
* NoAgeException : 非法年龄异常(框架: 很多JDK没有的异常,自定义)
*/
public class CustomDemo {
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("张三");
//        s.age = -18; // 非法访问,安全隐患,所以private int age;
        s.setAge(-18); //在方法里加安全机制
        System.out.println(s);
    }
}
class NoAgeException extends IllegalArgumentException{
    public NoAgeException(String msg){
        super(msg); //调用IllegalArgumentException,Ill..又调用自己的super。。
    }
}

如下是方法重写注意事项。
【Java21】异常,finally

package com.itheima06.notice;
import java.io.IOException;
/*
*   现象: 1. 父类 方法中声明编译异常【void method() throws IOException{}】,而子类没有声明编译异常 不会报错
*         2. 父类 方法中未声明编译异常,而子类有声明编译异常 会报错 !!!!!
* 
*   解释: 现象2 跟 多态冲突了
*       1.现象2在多态中,编译器只看左边,父类方法没有编译异常,以为没有编译异常,不需要处理
*       2.运行看右边,子类重写的方法运行时有编译异常 (编译异常要求编译时期必须处理)
*       冲突: 编译异常 绕过了 编译器 (编译器强制报错)
*/
public class NoticeDemo {
    public static void main(String[] args) throws IOException {       
        Fu fu = new Zi();  //编译看左边,运行看右边
        fu.method();
    }
}
class Fu{
    void method() {
    }
}
class Zi extends Fu{
    @Override
    void method() throws RuntimeException{//不报错 //throws IOException编译异常会报错,运行异常不报错。
    }
}

6.练习:常见异常

package com.atguigu.test01.review;
// 编写代码演示栈内存溢出 *Error(递归导致内存溢出)
public class TestError1 {
	public static void main(String[] args) {
		Son s = new Son();
		s.test(); //自己调用自己,不调用父类test()方法。java.lang.*Error
	}
}
class Father{
	public void test(){
		System.out.println("父类的");
	}
}
class Son extends Father{
	public void test(){ 
	    //调用父类的test();要用super.test()
		test();
		System.out.println("子类的");
	}
}
package com.atguigu.test01.review;
import java.util.ArrayList;
// 请编写代码演示OOM:OutOfMemoryError
public class TestError2 {
	public static void main(String[] args) {
		//1、答案一:创建一个超级大数组,
		//数组的长度的类型是int,Integer是int类型的一个包装类,Integer.MAX_VALUE是2的31次方-1
//		int[] arr = new int[Integer.MAX_VALUE];		

		//2、答案二:不断的创建对象
		ArrayList list = new ArrayList();//容器,用来装对象
		while(true){
			list.add(new Object());
		}
	}
}
public class TestFinallyNoReturn2 {
	public static void main(String[] args) {
		int num = getNum(4);
		System.out.println(num);//0,不是30
	}
	
	public static int getNum(int a){
		int result = 10;
		try{
			System.out.println(a/0); //直接跳到catch
			if(a > 0){
				result = 20;
				return result;
			}else if(a < 0){
				result = -20;
				return result;
			}else{
				return result;
			}
		}catch(Exception e){
			System.out.println("exception");
			result = 0;
			return result;
		}finally{
			result = 30;
			System.out.println("finally");
//			return result;//如果有这句,最后一行结果就变成30
		}
	}
}

【Java21】异常,finally
【Java21】异常,finally
【Java21】异常,finally
如下重写和抛异常两个报错。
【Java21】异常,finally
微信公众号:码农编程录
【Java21】异常,finally

上一篇:异常处理中关于finally的一些常见面试问题知识点解析整理


下一篇:try-catch-finally 和 return 是怎么执行的?