java基础第10天

Java异常 Exception

异常指的的在运行期出现的错误,在编译阶段出现的语法错误等,不能称之为异常。

编译类异常

必须处理之后才能正常编译(类找不到,IO异常,在API文档中明确写明throws的方法,必须要进行处理)

运行时异常(RuntimeException)

这种异常可以处理也可以不处理。

运行时异常的解决方法

遇到错误终止程序的运行,即不对异常进行处理

由程序员在编写程序的时,就考虑到错误的检测、错误的消息的提示,在抛给Java运行环境的时候,就将这个异常对象捕获,在进行处理。

使用try/catch语句捕获异常对象

public class Exception1 {

public static void main(String[] args){

int[] arr = {1,2,3};

try{

System.out.println(arr[4]); //加上try语块

}catch(Exception e){

System.out.println("发生数组越界");

}

}

}

try尝试:将可能发生异常的语句放入其中

catch捕获:当try块中的异常发生时,将产生一个异常对象,拿着这个对象去匹配catch块中的异常类,如果和catch中的类型匹配了,就执行这个catch块中的语句,这就是意味着,catch块可以有多个。

public class Exception2 {

public static void main(String[] args){

String str =null;

try{

System.out.println(str.length());

}catch(NullPointerException e){

System.out.println("空指针");

}catch(Exception e){

System.out.println("未知错误");

}

}

}

从程序上可以看出,一个try后可以加多个catch块,针对try语句块中发生的异常分别捕获,当然,只能有一个catch块碑执行,从执行的逻辑上看,和switch分支语句很相似。

进行异常捕获时,所有父类异常块都应该排在子类异常catch块的后面

访问异常信息

程序需要在catch块中访问异常对象的相关信息,可以通过访问catch块后的异常形参来获得,当Java运行时决定调用某个catch块来处理该异常对象时,会将异常对象赋值给catch块后的异常参数(即:异常类型的形参),程序即可通过该参数来获得异常的相关信息。

getMessage():返回该异常的详细描述信息

printStackTracwe():将异常的跟踪栈信息打印出来

printStackTrace(PrintStream s):将异常的跟踪栈信息输出到指定的输出流

getStackTrace():返回该异常的跟踪栈信息

import java.io.FileInputStream;   //导包

public class Exception3 {

public static void main(String[] args){

try{

FileInputStream fis = new FileInputStream("aa");

}catch(Exception e){

System.out.println(e.getMessage());  //打印异常信息

e.printStackTrace();                    //打印跟踪信息

}

}

}

编译时异常(必须捕获)

import java.io.FileInputStream;

public class Exception4 {

public static void main(String[] args){

FileInputStream in = null;

try{

in = new FileInputStream("aa");

}catch(Exception e){

e.printStackTrace();

}

}

}

finally回收资源

完整的异常处理结构

try{

业务处理语句

}catch(异常1 e1){

异常处理语句

}catch(异常2 e2){

异常处理语句

}

...

finally{

资源回收语句

}

注意:

在异常处理的机构中,只有try块是必须的,也就是说,如果没有try块,则不能有后面的catch和finally块,catch与finally二者中至少出现一个,当然也可以同时出现;finally位于所有catch块的后面

import java.io.FileInputStream;

import java.io.IOException;

public class Exception5 {

public static void main(String[] args){

FileInputStream fis = null;

try{

fis = new FileInputStream("aa");

}catch(IOException i){

System.out.println("发生异常");

}finally{

System.out.println("总会执行");

}

}

}

注意:System.exit(1);退出虚拟机 ####总结 - 除非在try块,catch块中调用了退出虚拟机的方法,否则不管在try块,catch块中执行怎样的代码,出现怎样的情况,finally块中的语句总会被执行。 - 通常情况下,不要在finally块中使用return或者throw等导致方法终止的语句,一旦在finally块中使用了return或者throw语句,将会导致try块,catch块中的return,throw语句失效。

public class Exception6 {

public static void main(String[] args){

int res = test();

System.out.println(res);   //  打印结果为3

}

public static int test(){

try{

System.out.println(2/0);

return 1;

}catch(Exception e){

return 2;

}finally{

return 3;

}

}

}

Checked异常和Runtime异常体系

Checked异常:编译时异常

Runtime异常:运行时异常

对于Checked异常有两种处理方式:

当前方法明确知道该如何处理该异常,程序应该使用try/catch块来捕获该异常,然后在对应的catch块中进行修复异常

当前方法不知道如何处理该异常,应在方法声明时抛出该异常

Runtime异常处理方式:

Runtime异常无需明显式抛出,如果储蓄需要捕获Runtime异常,也可以使用try/catch块来实现。

使用throws声明抛出异常,是对异常的一种处理方式

当前方法不知道如何处理这种类型的异常,该异常应该由上一级的调用者处理;如果main方法也不知道如何处理这种类型的异常,也可以使用throws继续声明抛出,将该异常交给JVM处理。JVM对异常的处理方法是打印异常的跟踪栈信息,并终止程序运行。

throws声明抛出异常的语法格式

方法签名+ throws Exception1,Exception2...

一旦一个方法使用throws关键字声明抛出了该异常,程序就无需使用try/catch块来捕获该异常了

import java.io.*;

public class Exception8 {

public static void main(String[] args) throws Exception{  //继续将异常抛出,交由JVM处理

test();

}

public static void test() throws Exception{   //抛出异常

FileInputStream fis = new FileInputStream("aa");

}

}

在定义一个方法时,使用throws声明抛出异常有一个限制

方法重写时,子类方法声明抛出的异常类型应该是父类声明抛出的异常类型的子类或者相同,子类声明抛出的异常不允许比父类方法声明抛出的异常大

总结

使用checked异常有如下不方便的地方

对于checked异常,必须显示的捕获并处理该异常,或者显式的声明抛出该异常,这样无疑增加了编程的复杂度

如果方法中显式抛出checked异常将会导致方法签名与异常耦合在一起,如果该方法时重写父类的方法,则该方法抛出的异常还会受到被重写方法所抛出异常的限制

如何自行抛出异常

在程序中抛出异常的话,需要使用到throw语句

首先要生成异常类对象,其语法格式如下:

IOException e = new IOException();

throw e;

对于Checked异常与Runtime异常的处理方法

如果throw语句抛出的异常为Checked异常,则该throw语句要么处于try块里显式捕获该异常,要么放在一个带throws声明抛出的方法中,即把该异常交给方法的调用者去处理;

如果throw语句抛出的是Runtime异常,则该语句无须放在try块中,也无须放在带throws声明的方法;

import java.io.IOException;

public class Exception9 {

public static void main(String[] args){

//被调用的checkedEx方法会抛出异常,并且是编译异常,必须用try,catch捕获,或者是在调用的方法上继续声明抛出

try{

checkedEx();

}catch(Exception e){

e.printStackTrace();

}

//被调用的方法会抛出运行时异常,可以完全不理会,由调用者处理,这里的调用者就是main方法

runtimeEx();

}

//方法中抛出的异常是编译异常,必须要进行处理:要么放在try块中,要么在方法声明上加上抛出声明

public static void checkedEx() throws IOException{

throw new IOException("checked Exception");

}

public static void runtimeEx(){

//方法中抛出的异常是运行时异常,可以处理,也可以不理会

throw new NullPointerException();

}

}

方法抛出异常的流程图,以(IOException--编译异常)为例

自定义异常类

定义异常类时通常需要提供两个构造方法,一个是无参的,一个是带有一个字符串的构造方法,这个字符串将作为该异常对象的描述信息,也就是对异常对象的getMessage方法的返回值

自定义一个异常类的语法如下

public class MyException extends Exception{

public MyException(){}  //空参构造

public MyException(String s){// 有参构造  字符串作为信息传递

super(s);  //调用父类Exception的构造方法

}

}

案例练习

/*

编写应用程序EcmDef.java,接收命令行的两个参数,要求不能输入负数,计算两数相除。

对数据类型不一致(NumberFormatException)

缺少命令行参数(ArrayIndexOutOfBoundsException

除0(ArithmeticException)

及输入负数(EcDef 自定义的异常)进行异常处理。

前几种异常,Java中都已经有相应的异常类了,但是最后一种对输入负数的异常,系统没有这样的异常定义,所以,这个异常应该是我们自定义的异常。

提示:

(1)在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。

(2)在main()方法中使用异常处理语句进行异常处理。

(3)在程序中,自定义对应输入负数的异常类(EcDef)。

(4)运行时接受参数 java EcmDef 20 10

//args[0]=“20” args[1]=“10”

(5)Interger类的static方法parseInt(String s)将s转换成对应的int值。

如int a=Interger.parseInt(“314”);    //a=314;

复习如何使用API文档,查看Integer类的方法

*/

public class Exception11 {

public static void main(String[] args){

try{

int a = Integer.parseInt(args[1]);

int b = Integer.parseInt(args[2]);

int res = dev(a,b);

System.out.println(res);

}catch(NumberFormatException nfe){

System.out.println("数据类型不一致");

}catch(ArrayIndexOutOfBoundsException a){

System.out.println("缺少命令行参数");

}catch(ArithmeticException ae){

System.out.println("除数不能为0");

}catch(MyException me){

System.out.println(me.getMessage());

}

}

public static int dev(int a,int b) throws MyException{

if(a<0||b<0){

throw new MyException("除数不能为负数");

}

return a/b;

}

}

//自定义异常类

class MyException extends Exception{

public MyException(){}

public MyException(String s){

super(s);

}

}

时间: 2024-10-27 12:46:27

java基础第10天的相关文章

Java基础问题10问

Java基础必须掌握的问题10问: 主要知识点: 定义类,字段,static修饰,局部,成员变量初始化, 继承,(非)检查异常,读写流,拷贝文件.. 1.如何定义一个类.字段.方法:如何创建类的对象: 答:类是java程序的组织单位,任何的java语句,都要写在类文件里面.(这么说不全对,package语句和import语句就可以写在外面,但编译之后一定是在类文件里面的) 类一般形式:class className{类体} 定义字段:Java中字段一般即指成员变量(数据库才说是字段) acces

夯实Java基础系列10:深入理解Java中的异常体系

目录 为什么要使用异常 异常基本定义 异常体系 初识异常 异常和错误 异常的处理方式 "不负责任"的throws 纠结的finally throw : JRE也使用的关键字 异常调用链 自定义异常 异常的注意事项 当finally遇上return JAVA异常常见面试题 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 - Java异常 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.c

Java基础系列10:内存操作流,管道流,合并流,压缩流以及回退流

前言:这篇文章将对几个"非主流"的IO流进行简单的介绍 一 内存操作流 内存操作流的主要作用是完成内存的输入和输出.比如说在某些情况下需要生成一些临时信息,而将这些临时信息保存在文件中不仅要进行文件的读写而且在功能完成之后还需要删除这个临时文件,因此比较麻烦,这时或许就需要用到内存操作流了. 需要用到的API是:ByteArrayInputStream和ByteArrayOutputStream,分别表示输入流和输出流,示例代码如下: package javase.io; import

java基础练习 10

import java.util.Scanner; public class Tenth { /*有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成最前面的m个数*/ public static void main(String[] args){ Scanner input=new Scanner(System.in); System.out.println("您将输入的数字个数为:"); int a=input.nextInt(); int[] array=new int[a

Java基础学习10

二维数组 数组为引用数据类型,默认值为null. 定义一个一维数组,格式为:int[] i = new int[]; 可以看出一维数组的每一个元素都为一个int型,那么二维数组就是原本是每一个元素现在改为每一个数组了,即为int[]. 所以二维数组的定义为: int[][] i = new int [4][5];//红色表示第二维 二维数组在内存中的结构: 数组中的异常: 1 数组下标越界: java.lang.ArrayIndexOutOfBoundsException int[] i = n

Java基础笔记10

类的设计分析: 1.根据需求抽取属性.(名词几乎都是属性) 2.属性私有化(private) 3.生成setter和getter方法 4.可以根据需要添加构造函数. 5.根据需求抽取其他方法.(动词几乎都是方法.) 6.方法中尽量避免输出语句,调用处输出. 构造方法. 特点: 方法名与类名相同.并且没有返回类型. 作用: 实例化对象. 初始化对象的属性值. 如果没有创建构造方法,那么系统会添加一个无参什么都不做的构造方法.一旦自定义了构造方法,那么 系统添加的构造方法就会消失. 普通方法的重载:

Java语言的基础知识10

第十二章(GUI事件) 1.GUI事件的处理机制是建立交互式应用程序的关键技术,其中事件是用在程序界面上的各种操作. 2.写程序的时候对于swing的一些空间譬如jprogressbar ,jtextfield等空间在全局中声明以后,用的时候一定要new 一下,自己经常忘记(由于对java理解不深) private  JTextField textField2; textField2 = new JTextField(); 3.事件在java语言中也是一种对象 4.监听器接受到事件之后,将委托指

Java基础10 接口的继承与抽象类(转载)

接口继承 接口继承(inheritance)与类继承很类似,就是以被继承的interface为基础,增添新增的接口方法原型.比如,我们以Cup作为原interface: interface Cup{    void addWater(int w);    void drinkWater(int w);} 我们在继承Cup的基础上,定义一个新的有刻度的杯子的接口,MetricCup 接口如下: interface MetricCup extends Cup{    int WaterContent

Java基础10:全面解读Java异常

Java基础10:全面解读Java异常 为什么要使用异常 首先我们可以明确一点就是异常的处理机制可以确保我们程序的健壮性,提高系统可用率.虽然我们不是特别喜欢看到它,但是我们不能不承认它的地位,作用. 在没有异常机制的时候我们是这样处理的:通过函数的返回值来判断是否发生了异常(这个返回值通常是已经约定好了的),调用该函数的程序负责检查并且分析返回值.虽然可以解决异常问题,但是这样做存在几个缺陷: 1. 容易混淆.如果约定返回值为-11111时表示出现异常,那么当程序最后的计算结果真的为-1111