在java中,所有的异常类型都是java.lang.Throwable的子类,在Throwable下面有两个异常的分支,一个是Exception一个是error;
Error指的是java运行时的内部错误和资源耗尽错误,应用程序不会抛出此类异常,这种内部错误一旦出现,除了告知用户程序终止之外,其他的也无能为力,例如堆栈溢出是这种错误的一例
1)运行时异常(非受查异常)都是 RuntimeException 类及其子类异常,例如NullPointerException,IndexOutOfBoundsException,ArithmeticException他是点击运行程序之后抛出的异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般由程序逻辑错误引起,程序应该从逻辑角度尽可能避免这类异常的发生。
2)非运行时异常(受查异常),他是在程序进行编译的时候就会抛出的异常,我们必须在程序运行之前进行处理,例如 IOException、ClassNotFoundException,CloneNotSupportedException,但是IOException又可以分为EOFException,FileNotFoundException
1.用try catch来进行捕获异常
try代码块中放的是可能出现异常的代码,catch代码块中存放的是出现异常后的处理行为,finally是用于代码块的善后处理工作,一般是在最后面执行;
1,不进行处理异常,就发现程序会终止在出现异常的地方,后面不会再继续执行,因为程序会把异常直接交给JVM来进行处理,这样的处理结果是,程序会抛出异常,并且不会再继续向下执行
int[] arr1={1,2,3};
System.out.println(arr1[0]);
System.out.println(arr1[3]);
System.out.println("hello");
2,但是此时当程序进行用try catch来进行包裹异常的时候程序会自己在catch中处理异常,这样处理的结果是程序会自动向下执行,但是一旦try中发现异常的语句,就会立即跳到catch语句里面,try之后代码块的语句不会执行,catch执行完毕之后会继续向下自动执行
int[] arr1={1,2,3};
try{
System.out.println(arr1[0]);
System.out.println(arr1[4]);
System.out.println("我爱我的家");
}catch(ArrayIndexOutOfBoundsException e)//这里面的ArrayIndexOutOfBoundsException不可以换成其他的异常,否则还是会交给JVM进行处理
{
}
System.out.println("我爱我的祖国");
最终我们打印的结果是1,我爱我的祖国
finally中的代码手机一定会被执行的,所以我们会优先执行finally中的return语句
catch也可以有多个,finally常常用于最后的善后工作,例如释放资源,无论是否发生异常,finally的代码块最终一定会被调用到
int[] arr1={1,2,3,4,5,6,7};
try{
arr1=null;
System.out.println("hehe");
System.out.println(arr1[5]);
System.out.println("heihei");
}catch(ArrayIndexOutOfBoundsException e)
{
e.printStackTrace();
System.out.println("此时发生了数组越界异常·");
}catch (NullPointerException e)
{
e.printStackTrace();
System.out.println("此时发生了空指针异常");
}
最终打印结果的值是hehe,此时发生了空指针异常
Scanner scanner=new Scanner(System.in);
try{
int num= scanner.nextInt();
System.out.println(10/num);
}catch(InputMismatchException e)
{
e.printStackTrace();
System.out.println("输入错误");
}catch (ArithmeticException e)
{
e.printStackTrace();
System.out.println("算数异常,可能0作为了除数");
}finally{
scanner.close();
System.out.println("finally代码块最终执行了");
}
0
算数异常,可能0作为了除数
finally代码块最终执行了
示例代码:用try回收资源
try(Scanner scanner=new Scanner(System.in)){
int num= scanner.nextInt();
System.out.println(10/num);
}catch(InputMismatchException e)
{
System.out.println("此时发生了输入错误");
}catch(ArithmeticException e)
{
System.out.println("此事发生了算数异常,可能0作为了分母");
}
}
如果此方法中没有合适的处理异常的方式,就会沿着调用栈向上进行传递
public static void func(int n)
{
System.out.println(10/n);
}
public static void main(String[] args) {
try{
func(0);
}catch(ArithmeticException e)
{
System.out.println("此时发生了算数异常");
}
}
最终交给了main函数来进行处理
但是如果说一直向上传递都没有合适的方法去处理异常(main函数里面都没有try Catch)那么最终就会交给JVM来进行处理(和我们最开始没有使用try catch是一样的)
public static void func(int n)
{
System.out.println(10/n);
}
public static void main(String[] args) {
func(0);
System.out.println(123);
}
这个程序最终什么结果都不会进行打印
public static int func()
{
int a=10;
try{
return a;
}catch(ArithmeticException e)
{
e.printStackTrace();
}finally{
System.out.println("1");
return 20;
}
}
public static void main(String[] args) {
int num=func();
System.out.println(num);
}
最终打印结果是1 20
下面我们来进行总结:
1)程序会先进行执行try中的代码
2)如果try中的代码出现了异常,就会结束try中的代码,看看是否与catch中的异常类型是否匹配,如果不能进行匹配,那么就会直接交给JVM来进行处理
3)如果没有找到匹配的异常类型,就会将异常向上传递到上层调用者;
4)无论是否找到匹配的异常类型,finally中的代码都会被执行掉,(在该方法结束之前执行)
5)如果上层调用者也没有处理了的异常,就会继续执行向上传递,一旦main()方法也没有合适的代码处理异常,就会交给JVM来进行处理,此时代码就会异常终止;
2.手动抛出异常
public static int func(int x)
{
if(x==0)
{
throw new ArithmeticException("hh");
}
return 1;
//return x/10;
}
public static void main(String[] args) {
int x=func(0);
System.out.println(x);
}
无论返回多少,程序啥都不会进行打印
public static void main(String[] args) {
throw new ArithmeticException("111");
}
int x=0;
if(x==0)
{
throw new UnsupportedOperationException("x==0我是不允许的");
}
3.处理受查异常
当一个代码中出现了受查异常,必须显式进行处理,如果一段代码可能会出现受查异常,那么也需要进行处理;
public static void main(String[] args) throws FileNotFoundException {
File file=new File("d:/22");
Scanner scanner=new Scanner(file);
System.out.println(scanner.nextLine());
}
1)使用try catch进行包裹
public static String readFile() {
Scanner scan=null;
try{
File file=new File("d:/22");
scan=new Scanner(file);
}catch(FileNotFoundException e)
{
e.printStackTrace();
}
return scan.nextLine();
}
public static void main(String[] args) {
String str=readFile();
System.out.println(str);
}
2)在方法名后面加上异常说明,相当于将处理动作交给上级调用者
public static String readFile() throws FileNotFoundException {
File file=new File("d:/22");
Scanner scanner=new Scanner(file);
return scanner.nextLine();
}
public static void main(String[] args) throws FileNotFoundException {
String str=readFile();
}
4.自定义异常
一个自定义异常继承了Exception就被称为受查异常,继承于RuntimeException就被称为非受查异常
static class MyException extends Exception{
public MyException(String message) {
super(message);
}
}
static class MyException1 extends RuntimeException
public MyException1(String message) {
super(message);
}
}
public static void func1(int x){
if(x==0)
{
try {
throw new MyException("这是我自己抛出的异常");//
} catch (MyException e) {
e.printStackTrace();
}
}
}
public static void func2(int x)
{
if(x==0){
throw new MyException1("x==0");//不需要进行try catch进行包裹
}
}
实例1:实现一个简单的用户登录功能
static class NameException extends Exception{
public NameException(String message)
{
super(message);
}
}
static class PasswordException extends Exception
{
public PasswordException(String message)
{
super(message);
}
}
private static final String name="李佳伟";
private static final String password="12503487";
public static void login(String name, String password) throws NameException, PasswordException {
if(!test.name.equals(name))
{
throw new NameException("您输入的用户名错误");
}
if(!test.password.equals(password))
{
throw new PasswordException("您输入的密码是错误的");
}
System.out.println("登陆成功");
}
public static void main(String[] args) {
try {
login("李佳伟","12503487");
} catch (NameException e) {
e.printStackTrace();
} catch (PasswordException e) {
e.printStackTrace();
}
}
示例2:使用while循环来进行类似于恢复异常的处理行为,他将不断重复,直到程序不在抛出异常
public static void main(String[] args) {
int i = 0;
while (i < 15) {
try {
if (i < 10) {
throw new UnsupportedOperationException("i现在还小于10");
}
} catch (UnsupportedOperationException e) {
e.printStackTrace();
System.out.println("第" + i + "次");
i++;
}
}
}