文章目录
前言
摸鱼了几天,重新开始学习= =。
这次是摸回JAVA基础的异常控制。之前一直都是直接用的IDEA的自动补全异常语句,但是隐约觉得这玩意还是得好好学习,所以今天抽空补补课。
学习网站是how2j,顺便复习复习IDEA上传到GIT的操作。(‾◡◝)
简介
异常的定义:导致程序的正常流程被终端的事件。
为啥要整这玩意:进行某个程序操作时,可能是一个潜在的错误操作,如果不预先做好异常处理,那么就会导致编译错误。
一. try、catch与finally
① try && catch
- 一个try对应一或多个catch。
- try的代码块中只要遇到一个异常,就会直接中断。
- 一组try && catch语句一般情况下只能抛出一个异常:因为遇到一个异常时,try代码块的运行就会直接中断,后面的触发异常语句不会被运行。不过可以通过其他方法来抛出多个异常,此处不展开说明。
- Exception类是所有异常类的父类。
因此,可以直接catch(Exception e),但是只限于只有一种异常的情况。 - 多异常代码块的处理:多个catch、一个catch
以上内容及更多内容可见以下两份代码块内容
public class one {
public static void main(String[] args)
{
// 此处不会报错,因为此时f只是一个定义了文件路径的File类,并没有真正访问这个路径
File f = new File("/Users/fwy/Downloads/jojo.jpg");
try
{
System.out.println("试图打开不存在的文件jojo.jpg");
new FileInputStream(f);
System.out.println("成功打开");
// }catch (FileNotFoundException e){ // FileNotFoundException:文件不存在 异常
}catch (Exception e){ // Exception:所有异常的父类,可以直接用于捕捉异常。
System.out.println("jojo.jpg不存在噢!");
// printStackTrace():这玩意是用来打印方法的调用痕迹的
// 控制台的橙色部分就是该函数的打印内容
// 在此例子中打印出了异常起始位置为第15行
e.printStackTrace();
// 打印 堆栈 痕迹
}
}
}
// 多异常捕捉
public class two {
public static void main(String[] args)
{
// 方法一:分别对不同异常进行catch
File f = new File("/Users/fwy/Downloads/QAQ.jpg");
try
{
System.out.println("试图打开不存在的文件QAQ.jpg");
new FileInputStream(f);
System.out.println("成功打开!");
int[] arr = new int[10];
System.out.println(arr[10]);
// 实际上只能捕捉到一个异常,捕捉到异常后就会直接中断
// 比如本例中运行到18行就会直接中断,数组越界部分不会涉及到
} catch (FileNotFoundException e)
{
System.out.println("文件不存在");
e.printStackTrace();
} catch (IndexOutOfBoundsException e)
{
System.out.println("数组访问越界");
e.printStackTrace();
}
// 方法二:直接放在同一个catch里
f = new File("/Users/fwy/Downloads/QVQ.jpg");
try
{
System.out.println("试图打开存在的文件QVQ.jpg");
new FileInputStream(f);
System.out.println("成功打开!");
int[] arr = new int[10];
System.out.println(arr[10]);
} catch (FileNotFoundException | IndexOutOfBoundsException e)
{
// 格式为 Exception1 | Exception2 e, IDE可以报出具体错误
// 使用 instanceof 来区分异常,用于进行不同异常的处理
if (e instanceof FileNotFoundException)
System.out.println("文件不存在");
else if (e instanceof IndexOutOfBoundsException)
System.out.println("数组访问越界");
e.printStackTrace();
}
}
}
② finally
- 可以不写
- 无论如何最后都会被执行
③ throws
- throw与throws区别:
throws:用于方法声明,代表异常出现的可能性,不一定会发生。
throw: 出现于方法体内,实际上地抛出了异常对象 - throws的使用情况:
方法一调用方法二,方法二有异常但是选择不处理,而是抛出给方法一,让方法一处理。
理解起来可能比较绕,可以参考以下代码:
这里是主函数调用方法一,方法一调用方法二的嵌套关系。
方法二出现异常后,由于方法二老渣男了,不想处理这个麻烦玩意,所以直接抛出给方法一。
方法一也不想当老实人,但是无奈打不过主函数,所以不能抛出给主函数,只能自己默默处理。
public class three {
// 同样不处理异常
public static void main(String[] args)
{
method1();
/*
try
{
method1();
} catch (FileNotFoundException e)
{
e.printStackTrace();
}
*/
}
// 选择在method1中处理异常
private static void method1() //throws FileNotFoundException
{
//method2();
try
{
method2();
} catch (FileNotFoundException e)
{
e.printStackTrace();
}
}
// 不处理异常,而是抛出异常
private static void method2() throws FileNotFoundException
{
File f = new File("/Users/fwy/Downloads/QAQ.jpg");
System.out.println("试图打开不存在的文件QAQ.jpg");
new FileInputStream(f);
System.out.println("成功打开");
}
}
不过其实我们也可以选择方法一继续抛出给主函数,最终只要有一个地方进行try-catch的异常处理即可。
补充:JVM 相关
- 抛出异常语句(throw)都是通过 athrow 指令来实现(指令码)。抛指令
- 异常捕获语句(catch)早期也是指令,但现在是通过异常表实现。抓打表
二. 异常的分类
① 分类解释与思维导图
- Exception是所有异常的父类,Throwable是Exception和Error的父类
- Exception 异常:是程序本身可以处理的异常
- Error 错误:是程序无法处理的错误,大多为JVM出现的问题
- Throwable可以被throws抛出,但是catch的也要是Throwable类
// 异常分类:1. 可查异常
// 2. 非可查异常:a.运行时异常 b.错误
public class one {
public static void main(String[] args)
{
// 1. 可查异常 CheckedException:必须处理的异常,catch | throws,否则编译错误
// 比如FileNotFoundException
File f = new File("/Users/fwy/Downloads/QAQ.jpg");
try
{
new FileInputStream(f);
System.out.println("打开成功");
}catch (FileNotFoundException e){
e.printStackTrace();
}
// 2. 运行时异常 RuntimeException:不是必须处理的异常,不用catch | throws也可以编译
// 比如NullPointException,ArrayIndexOutOfBoundsException等
// 设计原因:Java中此类错误太过普遍,都进行捕捉的话,代码可读性不好
int k = 5/0;
String s = null;
s.length();
// 3. 错误 Error:系统级别的异常,通常是内存溢出。同2一样不要求强制捕捉
StringBuffer sb = new StringBuffer();
for (int i = 0; i < Integer.MAX_VALUE; i++)
{
// 不断增加字符导致内存用光,OutOfMemoryError
sb.append('a');
}
}
}
思维导图
图片截自how2j
三. 自定义异常
定义:自定义一个异常类,继承Exception。
用途:用于自定义类中需要的异常,比如定义银行卡类,取款时可以抛出余额不足异常。
- 有参构造与无参构造:见代码,主要是Exception的getMessage()的使用。
class Hero{
String name;
float hp;
Hero(String name,float hp){this.name = name;this.hp=hp;}
public void attack(Hero h) throws HeroIsDeadException
{
if(h.hp == 0)
throw new HeroIsDeadException(h.name + "已经死了,别鞭尸了"); //使用throw而非throws抛出异常
}
class HeroIsDeadException extends Exception{
public HeroIsDeadException() { } // 默认构造,信息更少,但是更方便
public HeroIsDeadException(String msg) // 有参构造,导入异常原因,分析异常更方便
{
super(msg); // 可以使用getMessage()函数来获取具体异常信息
}
}
}
public class one {
public static void main(String[] args)
{
Hero garen = new Hero("盖伦",600);
Hero teemo = new Hero("提莫",0);
try{
garen.attack(teemo);
}catch (Hero.HeroIsDeadException e){
System.out.println("异常的具体原因:" + e.getMessage());
e.printStackTrace();
}
}
}
例子:Hero类的attack方法的isDeadException。
四. 上传代码到GIT
说明:记录一下操作步骤= =,还是不太熟悉。
① 首先在github新建一个仓库Java_Exception_Learn。
然后得到这个仓库的地址(URL),用于IDEA中设置
② 然后在IDEA的项目中设置
- VCS - 导入到版本控制 - 创建Git存储库:选择要上传的项目
- 右键项目 - Git - 添加
- 右键项目 - Git - Commit目录… :弹出窗口,在提交信息输入想备注的东西,然后Commit
- 继续弹出窗口,点击定义远程,在URL中输入步骤①的URL即可