Lesson16_异常

36 篇文章 0 订阅
33 篇文章 0 订阅

Lesson16_异常

异常是什么

程序运行过程中那些不正常的情况:比如,该输入整数,结果输入的不是整数。

比如,该解析的是yyyy年MM月dd日格式的日期字符串,结果传入的是“2018-11-29”

异常机制的本质

就是当程序出现错误,程序安全退出的机制。

会导致什么结果

整个程序直接结束。用户体验极差!!!

常见的异常有哪些

package com.lesson19.常见异常;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

// 用尽可能简短的代码把异常搞出来
public class Demo {
    public static void main(String[] args) {
        // 1.数组下标越界异常  ArrayIndexOutOfBoundsException
        int[] arr = {};
        // System.out.println(arr[0]);

        // 2.空指针异常   NullPointerException
        String str = null;
        // System.out.println(str.length()); // str的最大长度 字符的个数
        class Person{
            private String name;
            private int age;
            // 省略get\set、构造方法等
            public void test(){}
        }

        Person person = null;
        // person.test();  // p是null null就是不指向任何对象,也就是没有对象。没有对象,哪来的test()方法呢? 所以抛出Null Pointer Exception(NPE)

        // 3.算术异常   ArithmeticException: / by zero
//        System.out.println(3/0);

        // 4.类型转换异常   ClassCastException
        class Pet{}
        class Cat extends Pet{}
        class Dog extends Pet{}
        Pet p = new Cat();
        // Dog dog = (Dog) p;

        // 5.输入类型不匹配异常    InputMismatchException
        Scanner input = new Scanner(System.in);
        // int num = input.nextInt();

        // 6.字符串下标越界异常    StringIndexOutOfBoundsException
        String s = "abc";
        // System.out.println(s.charAt(3));

        // 7.解析异常   ParseException
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        /*try {
            Date date = sdf.parse("2018-11-29");
        } catch (ParseException e) {
            e.printStackTrace();
        }*/

        // 8.栈溢出   StackOverflowError
        test();
    }

    public static void test(){
        // System.out.println("我中有我:递归");
        test();// 自己调用自己
    }
}

java对异常的处理过程:

  • java是采用面向对象的方式来处理异常的。
  • 抛出异常:在执行方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象交给JRE
  • 捕获异常:JRE得到该异常后,寻找相应的代码来处理异常。JRE在方法调用栈中查找,从生成异常的方法开始回溯,只直到找到相应的异常处理代码为止。

防止中断

设计程序过程中,可以在可能出现异常(预见性)的地方提供异常的方式来防止程序的中断。

异常的分类

  • 非受查异常

    • 【阴柔】如果不作处理,编译器不会给出任何错误提示。在你程序运行期间,惹到了它,就会给你脸色
    • 需要凭借软件工程师的经验预判
    • RuntimeException是非受查异常类的鼻祖,另一派是Error
    • 派生于RuntimeException的异常,如被 0 除、数组下标越界、空指针等,其产生比较频繁,处理麻烦,如果显式的声明或捕获将会对程序可读性和运行效率影响很大。 因此由系统自动检测并将它们交给缺省的异常处理程序(用户可不必对其处理)。
    • 这类异常通常是由编程错误导致的,所以在编写程序时,并不要求必须使用异常处理机制来处理这类异常,经常需要通过增加“逻辑处理来避免这些异常”。
  • 受查异常

    • 【刚烈】如果不处理,就跟你没完,编译器会报错,无法运行
    • Exception是受查异常的代表,它的子类除了RuntimeException分支外,都是受查异常
  • Error-错误,由java虚拟机生成并抛出,程序不做任何处理,程序员也不能解决的问题,是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。

    • Error表明系统JVM已经处于不可恢复的崩溃状态中,我们不需要管它。
  • Exception-IoException、RuntimeException

注意事项

  • 在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适的异常处理器。
  • 运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。
  • 方法重写中声明异常原则:子类重写父类方法时,如果父类方法有声明异常,那么子类声明的异常范围不能超过父类声明的范围。
  • 要避免使用异常处理代替错误处理,这样会降低程序的清晰性,并且效率低下。
  • 处理异常不可以代替简单测试—只在异常情况下使用异常机制。
  • 不要进行小粒度的异常处理—应该将整个任务包装在一个try语句块中。
  • 异常往往在高层处理(先了解!后面做项目会说!) 。

如何处理异常(重要)

异常处理机制

  • try-catch-finally

    • try 监视,监视一段有异常风险的代码,可能会产生异常,也可能会正常执行。需要跟catch或者finally语句块一起使用,try-catch、try-finally、try-catch-finally

    • catch 如果try语句块抛出了异常,会寻找能处理这个异常的catch来处理异常,相应的catch语句块就会执行。一般是给用户提示,告知异常原因,可以有多个catch快。当catch语句块用于捕获多个异常时,将具体的异常放在前面,通用的异常放在后面,否则会编译报错,当前面异常都无法处理时,通过Exception处理,防止漏掉异常。

    • finally 具备执行的“坚决性”,就算它前面有return,也要等finally执行完毕后,才能return。如果try中有System.exit(0),会直接退出程序,一般用于释放资源。

      ​ 通常用于资源的释放。无论是否抛出异常,finally语句块可以确保执行

  • throw-throws

    • throw 扔出一个异常对象; 可以在任何地方使用,一般用于方法内部。
    • throws 声明一个异常类型; 在方法上声明本方法可能抛出的异常类型,由调用者去处理,实现类职能分离(此方法只关注要实现的功能,实现功能过程中会遇到的异常交由调用者处理)
    • 如果有可能抛出异常,需要在方法上通过throws声明,throw与throws一般配合使用。
  • 选取

    • 如果是内部原因导致的异常,则自己处理,try-catch-finally
    • 如果是传入的参数不合法,外部原因导致的异常,就算自己捕获了也解决不了问题。则throw-throws
    • 当有可能由于调用时方法参数导致的异常,将异常细化并抛出具体的异常,提示调用者参数问题。当方法在调用时不时由于传入参数导致的异常,尽量在该方法内将异常处理。

自定义异常(了解)

异常类最关键的是类名

大家会发现,异常类的类名往往都很长。目的是通过类名就能够大概判断出问题原因。

Java系统提供的异常类型虽然很多,但终究是不足的。所以才有了自定义异常。

如果想自定义一个受查异常,则继承Exception;

如果想自定义一个非受查异常,则继承RuntimeException;

错误轨迹栈的查看(了解)

飘红

Exception in thread "main" java.lang.NullPointerException: 空指针异常
	at com.lesson19.错误轨迹栈.Demo.d(Demo.java:22) // 这里才是异常的第一案发现场,优先查看
	at com.lesson19.错误轨迹栈.Demo.c(Demo.java:18)
	at com.lesson19.错误轨迹栈.Demo.b(Demo.java:14)
	at com.lesson19.错误轨迹栈.Demo.a(Demo.java:10)
	at com.lesson19.错误轨迹栈.Demo.main(Demo.java:6)
    
Exception in thread "main" java.util.InputMismatchException
	at java.util.Scanner.throwFor(Scanner.java:864) // 这个异常不是我们能控制的,不必查看
	at java.util.Scanner.next(Scanner.java:1485)
	at java.util.Scanner.nextInt(Scanner.java:2117)
	at java.util.Scanner.nextInt(Scanner.java:2076)
	at com.lesson19.常见异常.Demo.main(Demo.java:39) // 离异常最近的,属于自己的代码,优先查看

优先查看:距离异常最近的(最上面的)属于自己的代码。

★debug能力(注意培养)

  • System.out.println();

    • 有些代码的运行情况并非如我们预期的那样。不要想当然,打印出来看一下,有助于我们排查错误

      public static void main(String[] args) {
          int sum = 0;
          int i = 1;
          for(; i <= 10; i ++);{ // 错在哪儿了?
              System.out.println("i = "+i);
              sum += i;
          }
          System.out.println(sum); // sum == 11 ?!
      }
      
  • 单步调试

    • 如果已经确定错误的范围,而且范围比较小,此时可以使用单步调试
    • 步骤
      • 打断点 在行号后面单击鼠标左键
      • Step Into 单步调试,一行一行地执行
      • Step Return 误入方法时,想快速出去
      • Step Over 把方法调用当作一条语句直接执行完毕,不进入方法内部
  • 单元测试

    • 好的单元测试:单元测试能否通过,标志着对应的功能模块是否正常。

    • 业务代码和测试代码分离,互不干扰,而且可以重复测试。项目越大,单元测试的价值越高

    • https://www.cnblogs.com/huaxingtianxia/p/5563111.html

      // 需要导入的包和方法
      import static org.junit.jupiter.api.Assertions.assertEquals;
      import org.junit.jupiter.api.Test;
      
      // 测试方法演示
      @Test
      public void testXXX(){
          assertEquals(期望值,实际值)// 如果实际值与预期不符,则说明测试未通过,功能代码有问题
      }
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值