异常..
1.开发过程中的错误
在开发Java程序的过程中 会遇到各种各样的错误 一下是对错误的分类:
1.语法错误
如果产生了语法错误的话 那么就会导致编译失败 程序无法正常运行
2.逻辑错误
比如原本我想要进行加法运算 但是我将加法运算符写成了减法运算符 但是这个错误并不致命 也就是说 不会导致编译失败进而程序无法运行
3.运行时错误
就是程序运行过程中产生的以外 会导致程序终止运行 这个错误在Java中也叫做异常
程序如果产生了异常 一般我们称之为:抛出了异常 如果我们没有主动去处理他的话 那么他就会终止程序的运行
2.异常
上面说了 异常就是运行时抛出的错误 如果没有主动去处理他的话 那么就会导致程序的终止运行
在Java中 异常有很多种
所有的异常都是继承自java.lang.Throwable(虽然Throwable的后缀able写的有点像接口 但是实际上他是一个类)
如何防止程序抛出异常而导致其终止运行呢?try-catch来捕捉异常
3.异常的种类
我们可以分成两种异常 一种是检查型异常 一种是非检查型异常
前者的话 一般通过修改代码的方式难以避免 并且编译器会检查这个异常(如果开发者没有处理这个异常的话 那么编译器就会报错)
哪些是检查型异常呢?除了RuntimeException和Error以外的异常
后者的话 一般可以避免 并且编译器也不会进行异常的检查(如果开发者没有处理这个异常的话 那么编译器是不会报错的)
哪些是非检查型异常呢?RuntimeException和Error这些异常
1.常见的检查型异常
如果存在潜在的异常的话 那么就需要我们进行处理 处理的方式可以是try-catch 也可以是throws
1.可能会抛出FileNotFoundException异常(如果指定文件不存在的话 就会抛出FileNotFoundException这个异常 并且代码的修改无法左右文件的存在性 可以通过throws的方式处理这个异常)
static void test1() throws FileNotFoundException {
FileOutputStream fos = new FileOutputStream("D:\1.txt");
}
2.解析日期的时候可能会抛出ParseException异常(如果解析的对象的格式和SimpleDateFormat指定的格式不一致的话 那么就会抛出ParseException这个异常 代码的修改无法解决这个异常 可以通过throws的方式进行处理)
(SimpleDateFormat.format()主要用于对未格式化的Date进行格式化操作 并且返回一个字符串
SimpleDateFormat.parse()主要用于对已格式化的字符串进行解析操作 并返回一个Date)
static void test2() throws ParseException {
SimpleDateFormat fos = new SimpleDateFormat("yyyy-MM-dd");
fos.parse("2022年10月11日");
}
3.程序睡眠的代码可能会抛出InterruptedException异常 需要我们主动处理 否则编译器就会检查并且报错
static void test3() throws InterruptedException {
Thread.sleep(2000);
}
4.根据类名找到指定类 然后创建相应的类实例 其中的话 可能会抛出三个异常 一种是如果不存在指定类名的类的话 那么就会抛出ClassNotFoundException异常 一种是如果指定类中没有无参构造方法的话 那么就会抛出InstantiationException 一种是如果无参构造方法的权限为私有的话 那么外界无法访问 就会抛出IllegalAccessException
public class Dog {
}
static void test4() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class cls = Class.forName("Dog");
Dog dog = (Dog)cls.newInstance();// 调用Dog中的无参构造方法进行Dog的实例化操作
}
其中的话 我们如果只根据Dog找到指定的类是不现实的 因为如果这个项目中存在多个Dog类的话 那么你应该去找谁呢 不知道 所以只能够写清楚全名 才能够解决ClassNotFoundException异常 并且由于我们的构造方法是公有且无参的 所以现在就不会因为异常而导致程序终止运行
2.常见的非检查型异常-Error
1.程序运行过程中因为堆空间溢出导致抛出OutOfMemoryError异常
static void test1(){
System.out.println(1);
for(int i = 0; i < 200; ++i){
long[] a = new long[10_0000_0000];
}
System.out.println(2);
}
2.程序运行过程中因为栈空间溢出导致导致抛出StackOverFlowError异常
static void test2(){
test2();
}
3.常见的非检查型异常-RuntimeException
1.程序运行过程中因为空值调用导致抛出NullPointerException
static void test3(){
StringBuilder sb = null;
sb.append("abc");
}
2.程序运行过程中因为构造方法的格式不对导致抛出NumberFormatException
static void test4(){
Integer i = new Integer("abc");
}
3.程序运行过程中因为数组越界访问导致ArrayIndexOutOfBoundsException
static void test5(){
int[] array = {11, 22, 33};
System.out.println(array[3]);
}
4.程序运行过程中因为类型之间不能转换导致ClassCastException(java.lang.String不能转换为java.lang.Double 这是因为这两个不是子类和父类的关系)
static void test6(){
Object o = "123.4";
Double d = (Double)o;
}
4.异常的处理
程序如果产生了异常 我们一般称之为:抛出了异常
不管抛出的是检查型异常 还是非检查型异常 只要我们没有去处理异常的话 那么程序就会终止运行
异常有两种处理方式:1.try-catch 捕获异常
2.throws 将异常往上抛
第二种处理可以解决编译器的报错 但是不能解决程序的终止运行问题
第一种处理可以解决编译器的报错 也可以解决程序的终止运行问题
1.try-catch
如果代码2没有抛出异常的话 那么代码1和代码3都可以正常执行 所有的catch语句都不会被执行 代码4也可以正常执行
如果代码2抛出异常的话 那么代码1可以正常执行 但是代码3不可以正常执行 会选择匹配的catch语句进行执行 代码4也可以正常执行
另外值得注意的是:
父类型异常不能写在子类型异常之前(这是因为如果匹配的是子类型异常的话 那么只能执行父类型异常的catch语句 子类型异常的catch语句永远没有执行的机会 其存在也没有任何意义)
1.异常对象的常用方法
public class Main {
public static void main(String[] args){
// 典型的非检查型异常 因为你没有主动处理这个异常 编译器也不会报错 但是运行过程中执行到该语句时就会终止运行
try {
Integer i = new Integer("abc");
}catch(NumberFormatException e){
// 异常描述
System.out.println(e.getMessage());
// 异常名称+异常描述
System.out.println(e);
// 打印堆栈信息 涉及到函数调用 包括了异常名称+异常描述
e.printStackTrace();
}
System.out.println(2);
}
}
由于e.printStackTrace突出了函数调用的信息 所以我们可以清晰的看出抛出异常的代码的行数
并且这个方法的底层是调用了System.err
他和System.out在内容较长的情况下是会交织在一起进行打印操作的
2.一个catch可以捕获多种类型的异常
1.这是从Java7开始的语法 单个catch可以捕获多个异常
2.父类型异常和子类型异常共存的时候 保留父类型异常即可(这是因为如果父类型异常在子类型异常之前的话 并且抛出的是子类型异常的话 那么子类型异常将永远没有机会进行匹配 也就没有存在的意义)
3.异常是隐式final修饰的(也就是说不能对其进行再次赋值操作 传递参数对其赋值已经属于第一次赋值了 因为异常属于什么类型是不确定的 所以不可以对其贸然进行赋值操作)
2.finally
try或者catch执行完以后 一定会执行finally内部的语句
finally可以和try-catch搭配 也可以和try搭配
在finally中 经常编写一些关闭文件释放文件资源的代码
public class Main {
public static void main(String[] args) {
PrintWriter pw = null;
try {
pw = new PrintWriter("D:\1.txt");
pw.write("my name is 1");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} finally {
if (pw != null)
pw.close();
}
}
}
这段代码中 针对文件关闭 我们编写了一个finally进行代码的存放 但是由于抛出异常的缘故 导致pw为空 所以我们需要对pw进行判空操作 不然的话 又会触发空指针异常
1.finally的细节
如果jvm退出或者线程被杀死的情况下 finally就可能不会被执行
在try或者catch中使用了continue、break、return等语句的话 那么finally就会在这些语句执行之前得到执行
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 3; ++i) {
try {
System.out.println(i + "_try_1");
if (i == 2) continue;
System.out.println(i + "_try_2");
} finally{
System.out.println(i + "_finally");
}
}
}
}
上述这段代码执行的结果是:
1_try_1
1_try_2
1_finally
2_try_1
2_finally
3_try_1
3_try_2
3_finally
public class Main {
public static void main(String[] args) {
for (int i = 1; i <= 3; ++i) {
try {
System.out.println(i + "_try_1");
if (i == 2) break;
System.out.println(i + "_try_2");
} finally{
System.out.println(i + "_finally");
}
}
}
}
上述代码执行的结果是:
1_try_1
1_try_2
1_finally
2_try_1
2_finally
public class Main {
public static void main(String[] args) {
System.out.println(get());
}
static int get(){
try{
new Integer("abc");
System.out.println(1);
return 2;
}catch(Exception e){
System.out.println(3);
return 4;
}finally{
System.out.println(5);
}
}
}
上述代码的执行结果为:3 5 4
3.throws
throws的作用就是将异常抛给上层方法
public class Main {
public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException {
test();
}
static void test() throws FileNotFoundException, ClassNotFoundException {
PrintWriter pw = new PrintWriter("D:/1.txt");
Class cls = Class.forName("Dog");
}
}
从上述代码可以看出:test方法中将产生的异常抛给了main方法 然后main方法也将异常抛给了上层 至于上层是什么 等会会讲到
如果throws同时抛出了子类型异常和父类型异常的话 那么只要保留父类型异常即可(这是因为如果同时保留两个异常 并且父类型写在子类型之前的话 那么子类型异常永远得不到匹配 那么也就没有存在的必要了)
当然的话 对于异常的处理方式不止有throws一种解决途径 你还可以通过try-catch的方式对异常进行处理 并且不仅仅可以全部通过throws或者try-catch进行处理 而且可以一部分使用throws 一部分使用try-catch进行处理
public class Main {
public static void main(String[] args) throws FileNotFoundException{
PrintWriter pw = new PrintWriter("D:/1.txt");
try {
Class cls = Class.forName("Dog");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
1.throws的流程
public class Main {
public static void main(String[] args) throws FileNotFoundException {
method1();
}
static void method1() throws FileNotFoundException {
method2();
}
private static void method2() throws FileNotFoundException {
method3();
}
private static void method3() throws FileNotFoundException {
PrintWriter pw = new PrintWriter("D:/1.txt");
}
}
从上述的代码和配图我们可以知道 异常是一路像上传 最终传给了jvm 然后最后就会使得程序终止运行
2.throws的细节
如果子类重写父类的方法时
如果父类的方法没有throws异常的话 那么子类也不可以throws异常
如果父类的方法throws了异常的话 那么子类可以throws异常 也可以不throws异常
当子类选择throws异常的时候 它可以throws父类异常的同类型异常 也可以是子类型异常
5.异常的实例
public class Main {
public static void main(String[] args) throws FileNotFoundException {
System.out.println(1);
Integer i1 = new Integer("123");
System.out.println(2);
Integer i2 = new Integer("abc");
System.out.println(3);
}
}
上述代码中 打印结果为:1 2 不会打印3 这是因为Integer i2 = new Integer(“abc”);抛出了NumberFormatException异常
2.
public class Main {
public static void main(String[] args) throws FileNotFoundException {
System.out.println(1);
Integer i = new Integer("1234");
Object o = "3.14";
Double d = (Double)o;
System.out.println(2);
}
}
上述代码中 打印了1 但是不会打印2 这是因为Double d = (Double)o;抛出了ClassCastException异常
3.
public class Main {
public static void main(String[] args) throws FileNotFoundException {
Integer[] nums = {11, null, 22};
for(int num: nums){
System.out.println(num);
}
}
}
上述代码中 会打印11 但是不会打印null和22 这是因为包装类型转换成对应的基本类型Java会自动调用xxxvalue进行转换操作 但是空值是不可以调用方法 所以就抛出了NullPointerException异常
而且如果数组元素是引用类型的话 遍历推荐的写法为引用类型 并非对应的基本类型
1.打印的细节
public class Dog {
@Override
public String toString() {
return "Dog-666";
}
}
public class Main {
public static void main(String[] args) throws FileNotFoundException {
Dog dog1 = new Dog();
System.out.println(dog1);// Dog-666
Dog dog2 = null;
System.out.println(dog2);// null
}
}
上述代码的结果分别是:Dog-666和null
打印一个对象的本质是调用这个对象中的toString方法 但是空值调用显然是会抛出异常的 但是他却正常打印了 原因在于println方法的底层实现
其实对于println方法来说 如果参数为空的话 他会返回一个"null" 如果不空 她才会选择调用对象的toString方法
public class Main {
public static void main(String[] args) throws FileNotFoundException {
System.out.println(1);
try{
System.out.println(2);
Integer i = new Integer("abc");
System.out.println(3);
}catch(NumberFormatException e){
System.out.println(4);
}
System.out.println(5);
}
}
上述代码中 打印结果为1 2 4 5 不会打印3 这是因为Integer i = new Integer(“abc”);抛出了NumberFormatException异常
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!