一、异常
Java标准裤内建了一些通用的异常,这些类以Throwable为顶层父类。
Throwable又派生出Error类和Exception类。
错误:Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。
异常:Exception以及他的子类,代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心。
总体上我们根据Javac对异常的处理要求,将异常类分为2类。
非检查异常(unckecked exception):Error 和 RuntimeException 以及他们的子类。javac在编译时,不会提示和发现这样的异常,不要求在程序处理这些异常。所以如果愿意,我们可以编写代码处理(使用try...catch...finally)这样的异常,也可以不处理。对于这些异常,我们应该修正代码,而不是去通过异常处理器处理 。这样的异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。
检查异常(checked exception):除了Error 和 RuntimeException的其它异常。javac强制要求程序员为这样的异常做预备处理工作(使用try...catch...finally或者throws)。在方法中要么用try-catch语句捕获它并处理,要么用throws子句声明抛出它,否则编译不会通过。这样的异常一般是由程序的运行环境导致的。因为程序可能被运行在各种未知的环境下,而程序员无法干预用户如何使用他编写的程序,于是程序员就应该为这样的异常时刻准备着。如SQLException , IOException,ClassNotFoundException 等。
需要明确的是:检查和非检查是对于javac来说的,这样就很好理解和区分了。
二、异常举例及常见bug解决方案
错误定位方法:
当出现异常时可以根据提示查看对应异常类的API文档
根据提示信息可以找到出现异常的代码所属包及具体位置
三、RuntimeException
展开out包,存在.class字节码文件,证明代码已经经过编译了
这说明code语法并未出错且编译通过了,但代码在运行时出错,因此这种错误被称为运行时异常(RuntimeException)
四、try/catch的作用
使用 try 和 catch 关键字可以捕获异常。
try/catch 代码块放在异常可能发生的地方,try/catch代码块中的代码称为保护代码。
Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。
如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。
package com.google.study.throwable;
import java.io.*;
public class ExcepTest{
public static void main(String args[]){
try{
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
} catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
} finally{
System.out.println("异常捕获完成!");
}
}
}
五、NullPointerException空指针异常
Object的一个子类Objects中存在requireNonNull()的方法,用来判断一个对象为空时,抛出NullPointerException。
举个例子:
public class ExcepTest{
public static void main(String args[]){
int a[] = null;
System.out.println("Access element three :" + a[3]);
}
}
六、throws
throw一般会用于程序出现某种逻辑错误时程序员主动抛出某种特定类型的异常。
public static void main(String[] args) {
String s = "example";
if(s.equals("example")) {
throw new NumberFormatException();
} else {
System.out.println(s);
}
//function();
抛出异常:
Exception in thread "main" java.lang.NumberFormatException
at test.ExceptionTest.main(ExceptionTest.java:67)
throws是方法可能抛出异常的声明。(用在声明方法时,表示该方法可能要抛出异常)
当某个方法可能会抛出某种异常时用于throws 声明可能抛出的异常,然后交给上层调用它的方法程序处理。
public static void function() throws NumberFormatException{
String s = "example";
System.out.println(Double.parseDouble(s));
}
public static void main(String[] args) {
try {
function();
} catch (NumberFormatException e) {
System.err.println("非数据类型不能转换");
//e.printStackTrace();
}
}
结果如下:
非数据类型不能转换
七、throw和trycatch剖析
我们通常在编写代码自定义异常类时,将其定义为extends Exception,而非extends RuntimeException,
因为RuntimeException(运行时检测异常)通常是用户运行时才检测到的错误,
Exception(编译时检测异常)是编译时能够检测到的异常,并能够及时提示开发者
我们编写代码时就要保证代码在编译时就正常,因此多数情况下定义为extends Exception
自己定义一个异常类:
package com.google.study.throwable;
import java.lang.Exception;
public class FlemingException extends Exception {
public FlemingException() {
}
public FlemingException(String message) {
super(message);
}
public FlemingException(String message, Throwable cause) {
super(message, cause);
}
public FlemingException(Throwable cause) {
super(cause);
}
public FlemingException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.google.study.throwable;
import org.junit.Test;
public class FlemingExceptionTest {
public int sum(int a, int b) throws FlemingException {
if (a > 10 || b > 10 || a < 0 || b <0) {
// 抛出异常
throw new FlemingException("只能求0-10之内的加法!");
}
return a + b;
}
@Test
public void test() {
// 捕获异常
try {
int number = sum(100, 100);
} catch (FlemingException e) {
e.printStackTrace();
}
}
}
八、手写高端自定义异常
新建一个名为ErrorCode的interface
package com.google.study.throwable;
public interface ErrorCode {
/**
* 获取错误码
*/
String getCode();
/**
* 获取错误信息
*/
String getMsg();
}
新建一个名为FlemingCodeEnum的Enum
package com.google.study.throwable;
public enum FlemingCodeEnum implements ErrorCode {
NOT_FOUND_PAGE("404", "找不到网站资源"),
NOT_FOUND_FILE("888", "找不到文件异常"),
NOT_O_TEN("233", "只能求0-10之内的加法!"),
;
private final String code;
private final String msg;
FlemingCodeEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
@Override
public String getCode() {
return code;
}
@Override
public String getMsg() {
return msg;
}
}
更新名为FlemingException的类
package com.google.study.throwable;
public class FlemingException extends RuntimeException {
public FlemingException(ErrorCode errorCode) {
super(errorCode.getMsg());
}
}
更新名为FlemingException的类
package com.google.study.throwable;
import org.junit.Test;
public class FlemingExceptionTest {
public int sum(int a, int b) throws FlemingException {
if (a > 10 || b > 10 || a < 0 || b <0) {
throw new FlemingException(FlemingCodeEnum.NOT_O_TEN);
}
return a + b;
}
@Test
public void test() {
try {
int number = sum(100, 100);
} catch (FlemingException e) {
e.printStackTrace();
}
}
}