Feb 25&26 2020 异常相关

Feb 25&26 2020 异常相关

一、概述
package day0225_1;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
 * java.lang.Throwable类
 * 是所有错误或异常的父类
 * 1.Exception :异常 
 *   Exception类有一个重要的子类RuntimeException
 *   1) 运行时异常:  
 *   2) 非运行时异常 (编译异常):
 * 2.Error :错误 
 */
public class Error1 {
	public static void main(String[] args) /*throws ParseException*/ {
		// 一、 Exception中的非运行时异常
		/*    a.第一种处理方式 通过throws抛出
				 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
				 Date date = sdf.parse("2000-02-07"); // 这句会报错
				 System.out.println(date);
			  b.第二种处理方式 try catch
		*/
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date date = null;
		try {
			date = sdf.parse("2000-02-07");
		} catch (ParseException e) {
			e.printStackTrace();
		}
		System.out.println(date);

		// 二、 Exception中的运行时异常:RuntimeException
		int[] arr = { 1, 2, 3 };
		// System.out.println(arr[-10]); // 此时越界了 会报一个索引越界异常错误
		// 使用try catch处理异常
		try { // try中放置可能会出现异常的代码
			System.out.println(arr[-10]);
		} catch (Exception e) { // catch中放置异常的处理逻辑
			System.out.println(e); // 报错提示为:java.lang.ArrayIndexOutOfBoundsException: -10
			System.out.println("出错啦!!");
		}

		// 三、Error
		int[] arr1 = new int[999999999];
		// 报错:Java heap space 内存溢出
		// 处理的方式只有处理源代码
	}

}

        try { 
        // try中放置可能会出现异常的代码
		} catch (Exception e) { 
		// catch中放置异常的处理逻辑
		}
二、异常的产生过程

此次不予深究 若有需要以后再研究

三、异常的处理

Java异常处理的五个关键字:try、catch、finally、throw、throws

3.1 throw

throw:可以在指定的方法中抛出指定的异常

  • 作用:
    可以在指定的方法中抛出指定的异常
  • 使用格式:
    throw new xxxException(“异常产生原因”)
  • 注意:
    • throw关键字必须写在方法内部
    • throw关键字后边new的对象必须是Exception或者Exception的子类对象
    • 抛出后的处理规范
      • throw抛出指定的异常对象,我们就必须处理这个异常对象
      • throw关键字后边创建的是RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JVM处理(打印异常,中断程序)
      • throw关键字后边创建的是非运行时异常,我们就必须处理这个异常,要么throw要么try…catch

1.数组索引相关问题

package day0225_1;

public class Error2 {
	public static void main(String[] args) {
		int[] arr1 = null;
		getElement(arr1, 1);
		/*
		 * 第一组数据:数组非法 参数合法
		   Exception in thread "main" java.lang.NullPointerException: 数组为null!
		   at day0225_1.Error2.getElement(Error2.java:27)
		   at day0225_1.Error2.main(Error2.java:18)
		 */
		int[] arr2 = new int[3];
		getElement(arr2, -5);
		/*
		 * 第二组数据:数组合法 参数非法
		   Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 参数非法!
		   at day0225_1.Error2.getElement(Error2.java:20)
		   at day0225_1.Error2.main(Error2.java:8)
		 */
		int[] arr3 = null;
		getElement(arr3, -2);
		/* 
		 * 第三组数据:数组和索引参数均非法
		   此处没有后续参数非法的提示是因为在判断数组为空之后,程序已终止
		   Exception in thread "main" java.lang.NullPointerException: 数组为null!
		   at day0225_1.Error2.getElement(Error2.java:27)
		   at day0225_1.Error2.main(Error2.java:18)
		 */
	}

	private static void getElement(int[] array, int index) {
		// 对传递过来的数组array进行合法性校验,如果数组为空则抛出空指针异常,并提示方法调用者
		if (array == null) {
			throw new NullPointerException("数组为null!");
		}
		// 对传递过来的参数index进行合法性校验,如果参数非法,则抛出数组索引越界异常,并提示方法调用者
		if (index >= array.length || index < 0) {
			throw new ArrayIndexOutOfBoundsException("参数非法!");
		}
	}
}

2.Objects非空判断

package day0225_1;

import java.util.Objects;

public class Error3 {
	public static void main(String[] args) {
		Object a = null;
		demo(a);
	}

	private static void demo(Object obj) {
		// 判断传递过来的对象是否为空
		
		/*手写的方式
		if(obj == null) {
			throw new NullPointerException("对象为空");
		}
		*/
		
		// 可以直接调用Objects中的方法进行判断 抛弃手写 简化代码
		Objects.requireNonNull(obj,"对象为空"); // Exception in thread "main" java.lang.NullPointerException
	}
}

3.2 throws

throws:异常处理的一种方式

  • 作用:
    • 当方法内部抛出异常的时候,我们就必须处理这个异常
    • 使用throws关键字处理异常对象
      会把异常对象声明抛出给方法调用者处理
      即最终给JVM处理–>中断处理
  • 使用格式:
    方法声明时使用
修饰符 返回值类型 方法名(参数列表) throws{
      throw newAAAException("···");
      throw newBBBException("···");
   ······
}
  • 注意:
    • throws关键字必须写在方法声明处
    • throws关键字后边声明的异常必须是Exception或者是其子类
    • 方法内部如果抛出了多个异常对象
      那么throws后边必须也声明多个异常
      如果抛出多个异常有父子类关系,则只声明父类异常即可
    • 调用了一个声明抛出异常的方法,我们就必须处理声明的异常 可以选择交给别人处理或自己处理
      • 给方法调用者处理:使用throws声明抛出给方法调用者处理
        即最终给JVM处理–>中断处理
      • 自己处理异常:try…catch

需要注意的是:要尽量使用try…catch自己处理异常 因为交给虚拟机处理则会终止程序

3.2.1 throws 声明异常处理

第一种方式:用throws声明异常交给虚拟机处理

package day0225_1;

import java.io.FileNotFoundException;
import java.io.IOException;
/*
 * 需要注意的是 其实需要抛出两个异常:FileNotFoundException和IOException
 * 但是因为FileNotFoundException继承于IOException
 * 所以仅抛出父类IOException即可
 */
public class Error4 {
	public static void main(String[] args) throws IOException {
		readFile("d:\\a.txt");
	}

	//
	public static void readFile(String fileName) throws IOException {
		if (!fileName.endsWith("txt")) {
			throw new IOException("传递的文件后缀不是.txt");
		}

		if (!fileName.equals("c:\\a.txt")) {
			throw new FileNotFoundException("传递的文件路径不是c盘下的a.txt");
		}

	}
}
3.2.2 try…catch 捕获异常处理

第二种方式:利用try…catch捕获异常自己处理

        try { 
        // try中放置可能会出现异常的代码
		} catch (异常类名 变量名) { 
		// catch中放置异常的处理逻辑
		// 一般会把异常信息记录到一个日志中
		}
package day0225_1;

import java.io.IOException;

public class Error5 {
	public static void main(String[] args) throws IOException {
		try {
			readFile("d:\\a.jpg");
		} catch (IOException ioe) { // try中抛出什么异常对象,catch就会定义什么异常变量来接收
			System.out.println("传递的文件后缀不是.txt");
		}
		System.out.println("后续代码"); // 不管咋样 这句都执行
	}

	// 这儿的throws是把错误抛给了main方法叫main方法自己处理==
    // main方法用try...catch处理掉了异常==
	// 所以才有System.out.println("后续代码"); // 不管咋样 这句都执行
	public static void readFile(String fileName) throws IOException {
		if (!fileName.endsWith("txt")) {
			throw new IOException("传递的文件后缀不是.txt");
		}
		else {
			System.out.println("没问题!");
		}
	}
}

Throw类中的3个异常处理方法

  • String getMessage() 返回此 throwable 的简短描述
  • String toString() 返回此 throwable 的详细描述
  • void printStackTrace() JVM打印异常对象时默认调用此方法,打印的异常信息最为全面
package day0226;

import java.io.IOException;

public class Error1 {
	public static void main(String[] args) throws IOException {
		try {
			readFile("d:\\a.jpg");
		} catch (IOException ioe) {

			System.out.println(ioe.getMessage());
			// 输出:传递的文件后缀不是.txt
			System.out.println(ioe.toString());
			// 输出:java.io.IOException: 传递的文件后缀不是.txt
			System.out.println(ioe);
			// 输出:java.io.IOException: 传递的文件后缀不是.txt 默认调用toString
			ioe.printStackTrace();
			/*
			 * java.io.IOException: 传递的文件后缀不是.txt
			   at day0226.Error1.readFile(Error1.java:28)
			   at day0226.Error1.main(Error1.java:8)
			 */
		}
	}

	public static void readFile(String fileName) throws IOException {
		if (!fileName.endsWith("txt")) {
			throw new IOException("传递的文件后缀不是.txt");
		} else {
			System.out.println("没问题!");
		}
	}
}

3.3 finally代码块
  • 使用格式:
        try {
        业务实现代码
		} catch (Exception e) {
		异常处理块
		} finally {
		资源回收块
		finally块中的代码通常用于资源回收
		无论是否出现异常 trycatch是否有  return值 都会执行
		}
  • 注意事项
    • 必须和try一起使用
    • 一般用于资源释放(资源回收),无论程序是否异常,最后都要通过finally进行资源的释放
3.4 异常的3种处理方式
  • 多个异常的3种处理方式
    • 多个异常分别处理
      即多组try…catch
    • 多个异常 一次捕获、多次处理
      即一个try对应多个catch
      try块中把可能产生异常的语句的都写进去
      再写多个catch块处理多种异常
      • 需要注意的是catch里面定义的异常变量如果有子父类关系,则子类异常必须写在父类异常上边,否则就会报错
    • 多个异常 一次捕获、一次处理
      即就1组try…catch
3.5 finally中有return语句时

简单理解为:同组的try、catch、finally出现时 finally无论如何都会被执行,且总是在最后被执行
所以会产生的效果为:无论try中或者catch中return什么 如果finally中有return语句 则返回的永远是finally中return语句所返回的值
要避免这种情况的发生

package day0226;

public class Error2 {
	public static void main(String[] args) {
		String arr = test();
		System.out.println(arr);
		/*
		finally返回
		java.lang.ArrayIndexOutOfBoundsException: 100
		at day0226.Error2.test(Error2.java:12)
		at day0226.Error2.main(Error2.java:5)
		*/
	}
	private static String test() {
		try {
			int[] array = { 0, 0, };
			System.out.println(array[100]);
			return "try返回";
		} catch (Exception e) {
			e.printStackTrace();
			return "catch返回";
		} finally {
			return "finally返回";
		}
	}
}

3.6 子类与父类之间的异常
  • 如果父类抛出多个异常,子类重写父类方法时,
    • ①可以抛出和父类相同的异常
    • ②或是父类异常的子类异常
    • ③或不抛出异常
  • 如果父类未抛出异常则子类也不可抛出异常
    即此时子类若产生异常,则不可声明抛出,只能捕获处理
    记住一句话:当爹的要比儿子牛逼
package day0226;

import java.text.ParseException;

public class Father {
	public void test1() throws NullPointerException,ClassCastException {}
	public void test2() throws IndexOutOfBoundsException{}
	public void test3() throws ParseException{}
	public void test4() {}
}
class Son extends Father{
	// ①相同
	public void test1() throws NullPointerException,ClassCastException {}
	// ②异常的子类异常
	public void test2() throws ArrayIndexOutOfBoundsException{}
	// ③不抛出
	public void test3() {}
	// ④父类未抛出,则子类不可抛出,只能捕获处理
	public void test4()  {
		try {
			
		} catch (Exception e) {
			
		}
	}
}
四、自定义异常类

因为java提供的异常类不够实际使用
所以需要自己定义一些异常类

  • 格式:
public class XXXexception extends Exception()或者RuntimeException() {
    添加一个空参数的构造方法
    添加一个带异常信息的构造方法
}
  • 注意:
    • 一般以Exception结为,说明该类是一个异常类
    • 必须继承Exception或者RuntimeException
      • 继承Exception:非运行时异常
        必须处理,要么throws,要么try…catch
      • 继承RuntimeException:运行时异常
        无需处理,交给虚拟机进行中断处理
4.1自定义异常类的练习

模拟注册操作,如果用户名已存在,则抛出异常并提示:该用户名已被操作

package day0226;

import java.util.Scanner;

/*
 * 流程分析:
 * 1.使用数组保存已经注册过得用户名
 * 2.使用Scanner获取用户输入
 * 3.定义方法对用户输入进行判断
 *   遍历比较 
 *   1)相等为true则抛出自定义的异常RegisterException
 *   2)不相等为false
 */
public class TestRegisterException {
	static String[] usernames = { "AAA", "BBB", "CCC" };

	public static void main(String[] args) throws RegisterException {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入您的用户名");
		String someUsername = sc.next();
		checkUsername(someUsername);
	}

	public static void checkUsername(String username) throws RegisterException {
		for (String name : usernames) {
			if (name.equals(username)) {
				throw new RegisterException("用户名已存在,请重新注册");
			}
		}
		System.out.println("注册成功");
	}
}
/*
 * 输入BBB时 会输出
 * Exception in thread "main" day0226.RegisterException: 用户名已存在,请重新注册
	at day0226.TestRegisterException.checkUsername(TestRegisterException.java:28)
	at day0226.TestRegisterException.main(TestRegisterException.java:21)
 */
/*
 * 输入awfaw时 会输出注册成功
 */

具体参考:https://blog.csdn.net/qq_29229567/article/details/80773970

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值