Java从零开始学十九(异常)

一、什么是异常

从字面上讲,就是不正常的现实就是异常。

程序中的异常也是要在程序运行中才会偶尔发生。如果程序还没有运行,编译就报错,这种不叫异常,这种叫编译错误,通常是语法上的错误

二、java中异常

Java 提供了两类主要的异常:runtime exception 和checked exception。所有的checked exception 是从java.lang.Exception 类衍生出来的,而
runtime exception 则是从java.lang.RuntimeException 或java.lang.Error类衍生出来的。它们的不同之处表现在两方面:机制上和逻辑上

所有异常必须处理!在程序里可以抛异常,但是决不能把异常抛给最终用户。
BUG 在程序员手里还不是BUG,但是一旦交付,那么就是BUG

2.1、机制上

runtime exceptions:

  • 在定义方法时不需要声明会抛出runtime exception
  • 在调用这个方法时不需要捕获这个runtime exception
  • runtime exception 是从java.lang.RuntimeException 或
  • java.lang.Error 类衍生出来的。

checked exceptions:

  • 定义方法时必须声明所有可能会抛出的checked exception
  • 在调用这个方法时,必须捕获它的checked exception,不然就得
  • 把它的exception 传递下去
  • checked exception 是从java.lang.Exception 类衍生出来的

2.2、逻辑上

从逻辑的角度来说,checked exceptions 和runtime exception 是有不同的使用目的的。

checked exception 用来指示一种调用方能够直接处理的异常情况。checked exception 迫使你捕获它并处理这种异常情况。

而runtime exception 则用来指示一种调用方本身无法处理或恢复的程序错误。

三、程序中看异常

3.1、例一

package com.pb.demo6;

import java.util.Scanner;

/*
 * 求2个整数的商
 * 当异常发生时,程序如何处理
 */
public class Test1 {

    public static void main(String[] args) {
        //从键盘获得输入
    Scanner input=new Scanner(System.in);
    System.out.println("请输入被除数:");
    int num1=input.nextInt();
    System.out.println("请输入除数:");
    int num2=input.nextInt();
    int result=num1/num2;
    System.out.println(num1+"与"+num2+"的商:   "+result);  System.out.println("谢谢使用!");

    }

}

当输入除数不是0时,正常运行,但当输入的除数为0时,或者字符串时,就会报出异常:

请输入被除数:
2
请输入除数:
0
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.pb.demo6.Test1.main(Test1.java:18)
请输入被除数:
ffd
Exception in thread "main" java.util.InputMismatchException

同时也发现有异常发生时,最后的输出语句并没有执行

四、常见异常

java.lang.ArithmeticExecption
算术异常类。当出现异常的运算条件时,抛出此异常。比如程序中出现了“除以零”这样的运算,就会出这样的异常。对这种异常,大家就要好好检查一下自己程序中,涉及到数学运算的地方,公式是不是有不妥了

java.lang.NullPointerException
空指针异常类。简单地说就是调用了未经初始化的对象或者是不存在的对象。当应用程序试图在需要对象的地方使用null 时,抛出该异常这种情况包括:

  • 调用null 对象的实例方法
  • 访问或修改null 对象的字段
  • 将null 作为一个数组,获得其长度
  • 将null 作为一个数组,访问或修改其时间片
  • 将null 作为Throwable 值抛出

应用程序应该抛出该类的实例,指示其他对null 对象的非法使用

java.lang.ClassNotFoundException
找不到类异常。当应用程序试图使用以下方法通过字符串名加载类时,抛出该异常:

  • Class 类中的forName 方法
  • ClassLoader 类中的findSystemClass 方法
  • ClassLoader 类中的loadClass 方法

java.lang.ArrayIndexOutOfBoundsException
数组下标越界异常。用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引
现在程序中大多都有对数组的操作,因此在调用数组的时候一定要认真检查,看自己调用的下标是不是超出了数组的范围,一般来说,显示(即直接用常数当下标)调用不太容易出这样的错,但隐式(即用变量表示下标)调用就经常出错了,还有一种情况,是程序中定义的数组的长度是通过某些特定方法决定的,不是事先声明的,这个时候,最好先查看一下数组的length,以免出现这个异常

java.lang.IllegalArgumentException
方法的参数错误异常。抛出的异常表明向方法传递了一个不合法或不正确的参数
类库中的方法在一些情况下都会引发这样的错误,比如音量调节方法中的音量参数,如果写成负数就会出现这个异常,再比如g.setColor(int red,intgreen,int blue)这个方法中的三个值,如果有超过255 的也会出现这个异常因此一旦发现这个异常,我们要做的,就是赶紧去检查一下方法调用中的参数传递是不是出现了错误

java.lang.IllegalAccessException
没有访问权限异常。当应用程序试图反射性地创建一个实例(而不是数组)、设置或获取一个字段,或者调用一个方法,但当前正在执行的方法无法访问指定类、字段、方法或构造方法的定义时,抛出该异常对程序中用了package 的情况下要注意这个异常

java.lang.IncompatibleClassChangeError
不兼容的类变化错误。当正在执行的方法所依赖的类定义,发生了不兼容的改变时,抛出该错误一般在修改了应用中的某些类的声明定义,而没有对整个应用重新编译,而直接运行的情况下,容易引发该错误

java.lang.InstantiationError
实例化错误。当应用程序试图使用Java 的new 结构,来实例化一个抽象类或一个接口时,抛出该异常通常由编译器捕获此错误,如果类定义中存在不兼容的更改,则此错误
将只可能发生在运行时

java.lang.LinkageError
链接错误。该错误及其所有子类指示一个类在一定程度上依赖于另一个类;但是,在编译前一个类之后,后一个类发生了不相容的改变

java.lang.StackOverflowError
堆栈溢出错误。当一个应用递归调用的层次太深,而导致堆栈溢出时,抛出该错误

java.lang.NumberFormatException
数字格式异常。当试图将一个String 转换为指定的数字类型,而该字符串却不满足数字类型要求的格式时,抛出该异常

java.lang.RuntimeException
运行时异常。RuntimeException 是那些可能在Java 虚拟机正常运行期间抛出的异常的超类可能在执行方法期间抛出但未被捕获的RuntimeException 的任何子类,都无需在throws 子句中进行声明

java.io.IOException
输入输出异常。当发生某种I/O 异常时,抛出此异常。此类是失败或中断的I/O 操作生成的异常的通用类

java.io.FileNotFoundException
文件未找到异常。当试图打开指定路径名表示的文件失败时,抛出此异常
在不存在具有指定路径名的文件时,此异常将由FileInputStream、FileOutputStream 和RandomAccessFile 构造方法抛出。如果该文件存在,但是由于某些原因不可访问,比如试图打开一个只读文件进行写入,则此时这些构造方法仍然会抛出该异常

java.io.EOFException
文件已结束异常。当输入过程中意外到达文件或流的末尾时,抛出此异常
此异常主要被数据输入流用来表明到达流的末尾。注意,其他许多输入操作返回一个特殊值表示到达流的末尾,而不是抛出异常

java.lang.InterruptedException
被中止异常。当线程在活动之前,或活动期间处于正在等待、休眠或占用状态,且该线程被中断时,抛出该异常有时候,一种方法可能希望,测试当前线程是否已被中断,如果已被中断,则立即抛出此异常

五、异常处理

5.1、语法格式:

try{
    // 有可能出现异常的语句
}catch(异常类 异常对象){
    // 编写异常的处理语句
}[ catch(异常类 异常对象){
    // 编写异常的处理语句
} catch(异常类 异常对象){
    // 编写异常的处理语句
} …. ]
[finally{
    一定会运行到的程序代码 ;
}

主要搭配:try-catch、try-catch-finally、try-finally三种形式

5.2、多个异常

如果同时有多个catch块,Exception 必须放在最后一个catch块中

package com.pb.demo6;

import java.util.InputMismatchException;
import java.util.Scanner;

import javax.naming.AuthenticationException;

/*
 * 求2个整数的商
 * 当异常发生时,程序如何处理
 */
public class Test1 {

    public static void main(String[] args) {
        //从键盘获得输入
    try{
        Scanner input=new Scanner(System.in);
    System.out.println("请输入被除数:");
    int num1=input.nextInt();
    System.out.println("请输入除数:");
    int num2=input.nextInt();
    int result=num1/num2;
    System.out.println(num1+"与"+num2+"的商:   "+result);
    }catch(InputMismatchException e){
        System.out.println("输入的不是数字");
        e.printStackTrace();

    }catch(ArithmeticException e){
        System.out.println("除数不能为0");
        e.printStackTrace();
    }catch(Exception e){
        System.out.println("其它错误!");
        e.printStackTrace();
    }finally{
    System.out.println("谢谢使用!");
    }

    }

}
请输入被除数:
2
请输入除数:
0
除数不能为0
java.lang.ArithmeticException: / by zero
    at com.pb.demo6.Test1.main(Test1.java:22)
谢谢使用!

在finally中的语句,不管出不出异常都会被执行.

但如果在catch块中:执行System.exit(0);或者System.exit(-1);程序将直接结束,finally中的语句将不会执行

5.3、Java的异常处理机制

在整个java的异常处理中,实际上也是按照面向对象的方式进行处理,处理的步骤如下:

  • 一旦产生异常,则首先会产生一个异常类的实例化对象;
  • 在try语句中对此异常对象进行捕捉;
  • 产生的异常对象与catch语句中的各个异常类型进行匹配,如果匹配成功,则执行catch语句中的代码

六、抛出异常

6.1、throws关键字

在定义一个方法的时候可以使用throws关键字声明,使用throws声明的方法表示此方法不处理异常,而交给方法的调用处进行处理 。

throws使用格式

public 返回值类型 方法名称(参数列表…) throws 异常类{}

package com.pb.demo6;

import java.util.InputMismatchException;
import java.util.Scanner;

import javax.naming.AuthenticationException;

/*
 * 求2个整数的商
 * 当异常发生时,程序如何处理
 */
public class Test2 {

    public static void main(String[] args) {
        try {
            divide();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    //除法运算
  public static void divide  () throws Exception{
     //从键盘获得输入
        Scanner input=new Scanner(System.in);
    System.out.println("请输入被除数:");
    int num1=input.nextInt();
    System.out.println("请输入除数:");
    int num2=input.nextInt();
    int result=num1/num2;
    System.out.println(num1+"与"+num2+"的商:   "+result);
  }
}

6.2、throw关键字

与throws不同的是,可以直接使用throw抛出一个异常。抛出的时候直接抛出异常类的实例化对象即可

package com.pb.demo6;
/*
 * 人类
 */
public class Person {
            private String name;
            private String sex;
            private int age;
            public String getName() {
                return name;
            }
            public void setName(String name) {
                this.name = name;
            }
            public String getSex() {
                return sex;
            }
            public void setSex(String sex) throws Exception {
                if(sex.equals("男") || sex.equals("女")){
                    this.sex = sex;
                }else{
                    throw new Exception("性别只能是男或者女");
                }

            }
            public int getAge() {
                return age;
            }
            public void setAge(int age) {
                if(age>=0 && age<=150){
                this.age = age;
                }else{
                    try {
                        throw new Exception("年龄只能在0-150岁之间!");
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
            public void printSelf(){
                System.out.println("姓名:"+this.name+"             性别:"+this.sex+"     年龄:"+this.age);
            }

}
package com.pb.demo6;

public class PersonTest {

    public static void main(String[] args) {
        Person p=new Person();

        try {
            p.setName("张三");
            p.setSex("不男不女");
            p.setAge(200);
            p.printSelf();
        } catch (Exception e) {
            e.getMessage();
            e.printStackTrace();
        }

    }

}

七、自定义异常

在Java中已经提供了大量的异常类,但是这些异常类有些时候也很难满足开发者的要求,所以此时用户可以根据自己的需要定义自己的异常类,定义异常类,只需要继承Exception类即可。

当然可以继承其它的如:Exception,Throwable,RuntimeException及其子类,其中继承Exception,Throwable,效果,如果不要求调用者一定要处理抛出的异常可以继承RuntimeException及其子类

调用时只需要throw new 自定义异常名(信息)

package com.pb.demo6;

public class MyException extends Exception {

    public MyException() {
        super();
        // TODO Auto-generated constructor stub
    }

    public MyException(String message, Throwable cause,
            boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
        // TODO Auto-generated constructor stub
    }

    public MyException(String message, Throwable cause) {
        super(message, cause);
        // TODO Auto-generated constructor stub
    }

    public MyException(String message) {
        super(message);
        // TODO Auto-generated constructor stub
    }

    public MyException(Throwable cause) {
        super(cause);
        // TODO Auto-generated constructor stub
    }

}
package com.pb.demo6;
/*
 * 人类
 */
public class Person {
            private String name;
            private String sex;
            private int age;
            public String getName() {
                return name;
            }
            public void setName(String name) {
                this.name = name;
            }
            public String getSex() {
                return sex;
            }
            public void setSex(String sex) throws Exception {
                if(sex.equals("男") || sex.equals("女")){
                    this.sex = sex;
                }else{
                    throw new MyException("性别只能是男或者女");
                }

            }
            public int getAge() {
                return age;
            }
            public void setAge(int age) {
                if(age>=0 && age<=150){
                this.age = age;
                }else{
                    try {
                        throw  new MyException("年龄只能在0-150岁之间!");
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
            public void printSelf(){
                System.out.println("姓名:"+this.name+"             性别:"+this.sex+"     年龄:"+this.age);
            }

}
package com.pb.demo6;

public class PersonTest {

    public static void main(String[] args) {
        Person p=new Person();

        try {
            p.setName("张三");
            p.setSex("不男不女");
            p.setAge(200);
            p.printSelf();
        } catch (Exception e) {
            e.getMessage();
            e.printStackTrace();
        }

    }

}

com.pb.demo6.MyException: 性别只能是男或者女

这时获得的异常就是我们自定义的异常

时间: 2024-10-11 23:39:25

Java从零开始学十九(异常)的相关文章

Java从零开始学十四(包和访问控制)

一.java中的包 Java文件的组织形式Windows中的文件功能类似 在开发比较大的项目时,不可能只涉及到一个java文件,可能要创建几十,甚至几百个java文件,这个时候,我们就可以使用包,把相关的java文件放在一起,利用包来方便,快捷,有效的管理这些文件 包的引入还可以避免命名冲突的问题,不同包下的类名可以同名 二.定义包 package 包名 这条语句必须放在java源程序的第一行,前面不能有任何可执行代码,当然注释除外 包可以创建多层次的,不同层次之间用点(.)隔开和windows

Java从零开始学十六(多态)

一.什么是多态 多态性是指允许不同类的对象对同一消息作出响应.多态性包括参数化多态性和包含多态性.多态性语言具有灵活.抽象.行为共享.代码共享的优势,很好的解决了应用程序函数同名问题.多态有两种表现形式:重载和覆盖首先说重载(overload),是发生在同一类中.与什么父类子类.继承毫无关系.标识一个函数除了函数名外,还有函数的参数(个数和类型).也就是说,一个类中可以有两个或更多的函数,叫同一个名字而他们的参数不同.他们之间毫无关系,是不同的函数,只是可能他们的功能类似,所以才命名一样,增加可

Java从零开始学十八(抽象类和接口)

一.什么是抽象类和接口 抽象类.接口与类是一个层次的概念,是java中极其重要的概念. 抽象类是从多个类中抽象出来的公共模板,提供子类均具有的功能. 接口是从多个类中抽象出来的规范,体现的是规范和实现分离的原则,同时也有效的解决了java单重继承的缺陷 二.抽象类 2.1.抽象类与普通类的区别 抽象类的class前面有abstract关键字,而普通类没有 /* * 抽象类 */ public abstract class Person1 {} /* * 普通类 */ public class P

Java从零开始学十五(继承)

一.继承作用 继承使用复用以前的代码非常容易,能够大大的缩短开发周期,降低开发成本,同时增加程序的易维护性 继承使重一个类A能够直接使用另外一个类B的属性和方法的一种途径 类A可以有自己的属性和方法 二.继承实现 类的继承格式 在Java中使用extends关键字完成类的继承关系,操作格式: class 父类{} // 定义父类 class 子类 extends 父类{} // 使用extends关键字实现继承 package com.pb.person; /* * 父类 */ public c

Java从零开始学十(Arrays类对数组的常用方法)

一.Arrays类常用方法 二.简单例子 package com.pb.demo1; import java.util.Arrays; /* * Arrays工具类的中的几个常用方法 * 1.copyof * 2.toString * 3.equals * 4.sort * 5.fill * 6.binarySearch */ public class ArraysTest { public static void main(String[] args) { String [] arry1={"

Java从零开始学十二(构造方法)

一.构造方法 构造方法的主要目的是为类中的属性初始化 二.构造方法的定义格式 class 类名称{ 访问权限 类名称(类型1 参数1,类型2 参数2,…){ 程序语句 ; …    // 构造方法没有返回值 } } 在构造方法的声明中读者一定要牢记以下几点: · 构造方法的名称必须与类名称一致 · 构造方法的声明处不能有任何返回值类型的声明 · 不能在构造方法中使用return返回一个值 class Person { private String name; // 声明姓名属性 private

Java Web总结十九Filter过滤器

一.Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,Web开发人员通过Filter技术,对Web服务器管理的所有Web资源:例如Jsp,Servlet,静态图片文件或静态HTML文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制.过滤敏感词汇.自动登录.压缩响应信息等一些高级功能. Servlet API中提供了一个Filter接口,开发Web应用时,如果编写的Java类实现了这个接口,则把这个Java类称之为过滤器Filter.通过

“全栈2019”Java第三十九章:构造函数、构造方法、构造器

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第三十九章:构造函数.构造方法.构造器 下一章 "全栈2019"Java第四十章:this关键字 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习小组&q

“全栈2019”Java第八十九章:接口中能定义内部类吗?

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第八十九章:接口中能定义内部类吗? 下一章 "全栈2019"Java第九十章:内部类可以向上或向下转型吗? 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学