【java快速入门-异常处理篇】- 异常简介

(多看多听多记多写)

异常处理部分

java的异常

一个健壮的程序必须处理各种各样的错误。错误是指,当程序调用某个函数的时候,如果失败了,就表示错误。

在java中解决判断错误或者获知调用失败的信息,大致有两种方法:

方法一:自定义返回错误码

例如,处理一个文件,如果有错误,我们可以通过函数返回值来确定,是什么错误,返回0则说明成功。

int code = processFile("D:\\test.txt");//processFile是自定义的一个处理文件的函数
if (code == 0) {
    // ok:
} else {
    // error:
    switch (code) {
    case 1:
        // file not found:
    case 2:
        // no read permission:
    .........//自定义其他错误类型
    default:
        // unknown error:
    }
}

但是这种方法想要处理错误,就会很麻烦

方法二:java程序中提供一个异常处理机制

Java内置了一套异常处理机制,总是使用异常来表示错误。

异常是一种class,因此它本身带有类型信息。异常可以在任何地方抛出,但只需要在上层捕获,这样就和方法调用分离了。例如:

try {
    String s = processFile(“C:\\test.txt”);
    // ok:
} catch (FileNotFoundException e) {
    // file not found:
} catch (SecurityException e) {
    // no read permission:
} catch (IOException e) {
    // io error:
} catch (Exception e) {
    // other error:
}

java的异常是class,同时也包含继承关系

从图中可以看出来,Throwable是异常体系的根,它继承自ObjectThrowable有两个体系:ErrorException

Error表示严重的错误,程序对此一般无能为力,例如(错误出现在内存中):

  • OutOfMemoryError:内存耗尽

  • NoClassDefFoundError:无法加载某个Class

  • StackOverflowError:栈溢出

Exception则是运行时的错误,它可以被捕获并处理。例如:

一些异常是应用程序逻辑处理的一部分,应该捕获并处理。例如:

  • NumberFormatException:数值类型的格式错误
  • FileNotFoundException:未找到文件
  • SocketException:读取网络失败

还有一些异常是程序逻辑编写不对造成的,应该修复程序本身。例如:

  • NullPointerException:对某个null的对象调用方法或字段
  • IndexOutOfBoundsException:数组索引越界

根据继承关系图可以看出,Exception又分为两大类

  1. RuntimeException以及它的子类;(RuntimeException:运行时异常,这种异常我们不需要处理,完全由虚拟机接管。比如我们常见的NullPointerException,我们在写程序时不会进行catch或throw。)
  2. RuntimeException(包括IOExceptionReflectiveOperationException等等)(受检查的异常,这种异常是强制我们catch或throw的异常。你遇到这种异常必须进行catch或throw,如果不处理,编译器会报错。)

并且java规定

  • 必须捕获的异常,包括Exception及其子类,但不包括RuntimeException及其子类,这种类型的异常称为Checked Exception。(必须进行catch或throw

  • 不需要捕获的异常,包括Error及其子类,RuntimeException及其子类。

捕获异常

捕获异常使用try...catch语句,把可能发生异常的代码放到try {...}中,然后使用catch捕获对应的Exception及其子类,例如:

//try...catch案例
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        byte[] bs = toGBK("中文");
        System.out.println(Arrays.toString(bs));
    }

    static byte[] toGBK(String s) {
        try {
            // 用指定编码转换String为byte[]:
            return s.getBytes("GBK");
        } catch (UnsupportedEncodingException e) {
            // 如果系统不支持GBK编码,会捕获到UnsupportedEncodingException:
            System.out.println(e); // 打印异常信息
            return s.getBytes(); // 尝试使用用默认编码
        }
    }
}

如何不使用try...catch语句直接开始转换的话

    static byte[] toGBK(String s) {
        return s.getBytes("GBK");
    }

编译器会报错,错误信息类似:

unreported exception UnsupportedEncodingException; must be caught or declared to be thrown,

并且准确地指出需要捕获的语句是return s.getBytes("GBK");

意思是说,像UnsupportedEncodingException这样的Checked Exception,必须被捕获。

这是因为String.getBytes(String)方法定义是:

public byte[] getBytes(String charsetName) throws UnsupportedEncodingException {
    ...
}

注意:在方法定义的时候,使用throws Xxx表示该方法可能抛出的异常类型。调用方在调用的时候,必须强制捕获这些异常,否则编译器会报错

当然java提供一种方法,可以让我们不捕获它,而是在方法定义处用throws表示toGBK()方法可能会抛出UnsupportedEncodingException,就可以让toGBK()方法通过编译器检查:

    static byte[] toGBK(String s) throws UnsupportedEncodingException {
        return s.getBytes("GBK");
    }

但是这样修改的话还需要再主程序中进行捕获,因为byte[] bs = toGBK("中文");。因为在main()方法中,调用toGBK()没有捕获它声明的可能抛出的UnsupportedEncodingException

// try...catch
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        try {
            byte[] bs = toGBK("中文");
            System.out.println(Arrays.toString(bs));
        } catch (UnsupportedEncodingException e) {
            System.out.println(e);
        }
    }

    static byte[] toGBK(String s) throws UnsupportedEncodingException {
        // 用指定编码转换String为byte[]:
        return s.getBytes("GBK");
    }
}

可见,只要是方法声明的Checked Exception不在调用层捕获,也必须在更高的调用层捕获。所有未捕获的异常,最终也必须在main()方法中捕获,不会出现漏写try的情况。这是由编译器保证的。main()方法也是最后捕获Exception的机会。

当然java还提供一种办法,直接将mian()定义为throws Exception。

// try...catch
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Main {
    public static void main(String[] args) throws Exception {
        byte[] bs = toGBK("中文");
        System.out.println(Arrays.toString(bs));
    }

    static byte[] toGBK(String s) throws UnsupportedEncodingException {
        // 用指定编码转换String为byte[]:
        return s.getBytes("GBK");
    }
}

因为main()方法声明了可能抛出Exception,也就声明了可能抛出所有的Exception,因此在内部就无需捕获了。代价就是一旦发生异常,程序会立刻退出

在捕获之后尽可能的将异常记录下来,捕获后什么都不做的方式是非常不好的

static byte[] toGBK(String s) {
    try {
        return s.getBytes("GBK");
    } catch (UnsupportedEncodingException e) {
        // 先记下来再说:
        e.printStackTrace();
    }
    return null;

所有异常都可以调用printStackTrace()方法打印异常栈,这是一个简单有用的快速打印异常的方法

小结

1.Java使用异常来表示错误,并通过try ... catch捕获异常;

2.Java的异常是class,并且从Throwable继承;

3.Error是无需捕获的严重错误,Exception是应该捕获的可处理的错误(除RuntimeException以外);

4.RuntimeException无需强制捕获,非RuntimeException(Checked Exception)需强制捕获,或者throws声明

5.不推荐捕获了异常但不进行任何处理,一种简单的快速打印异常的方法printStackTrace()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值