1.异常概述与异常体系结构
怎么处理代码运行中的异常
1.Java程序执行过程中所发生的异常分为两类
1.1 Error:Java虚拟机无法解决的严重问题。如JVM系统内部错误、资源严重情况。如StackOverflowError(栈溢出)、oom(堆溢出)、一般不编写针对性代码进行处理。
1.2 Exception:空指针访问、试图读取不存在的文件、网络连接中断、数组角标越界
→1.编译时异常
→2.运行时异常
2.常见异常
运行时异常
1.空指针访问(NullPointerExcepton)
test te[] =null;
System.out.println(te[0]);
2.角标越界(ArrayIndexOutOfBoundsException)
@Test
public void Method(){
String arr[]=new String[10];
System.out.println(arr[10]);
}
}
3.类型转换异常(ClassCastException)
public void Method(){
Integer k =10;
Object object=k ;
String l = (String)object;
}
4.数值形式异常(NumberFormatException)
@Test
public void Method(){
String aa ="abc";
int bb;
bb=Integer.parseInt(aa);
}
5.输入不匹配(InputMismatchException)
Father father =new Father();
Scanner scanner =new Scanner(System.in);
scanner.nextInt();
7.算数异常(ArichmeticException)
@Test
public void Method(){
int a =10;
int b =0;
System.out.println(a%b);
}
编译时异常
1.IOException(IO流异常)
2.FileNotFoundException(文件没发现)
3.ClassNotFoundException(类没有发现)
3.异常处理机制一:try-catch-finally
为什么用异常处理机制
当我们写代码的时,难免遇到报错,如果不是特别的无法处理的栈溢出、堆溢出等error类错误,我们可以预见并处理,都用if-else 会使得代码可读性变差,这时候引用try-catch-finally来处理这些异常。
两个方式的大体使用区别
try-catch-finally 处理一个当前能解决的问题
如无法解决使用throws 丢到上一级解决
try-catch-finally的使用
过程
抛:一旦出现异常,就会再异常代码生成一个对应异常类的对象,并抛出。一旦派出后,其后的代码不再执行。
接:try-catch-finally / throws
格式
test te[] =null;
try {
System.out.println("我来找问题");
System.out.println(te[0]);
}catch (NullPointerException e){
te=new test[10];
System.out.println("这是空指针问题");
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("数值角标越界?");
}catch (InputMismatchException e){
System.out.println("对不起,您输入的值有误");
}catch (NumberFormatException e){
System.out.println("对不起,不能这样转换");
}catch (ClassCastException e){
System.out.println("这样强转有误");
}
catch (Exception e){
System.out.println("我是异常的父类,不能放到前面");
}finally {
System.out.println("问题解决了");
}
}
说明
1.finally 不是必须的。
2.try将出现异常的代码包装起来,然后找到解决问题的catch 处理,处理完成后跳出异常处理(在没有写finally的情况下)。
3.不可以把catch异常们的父类放到上面,会报错,因为这样到不了子类。如果没有子父类关系,谁在上谁在下无所谓
4.可以通过e来调用两个方法 打印输出get.message 或直接调用(void类型)stackchase 来获取出错的具体情况
5.在try内声明的变量,出了try结构后不能被调用。try内部每个catch 独立不共享变量,但是外部的变量可以在try catch内部使用
6.try-catch 可以嵌套
体会:使用try-catch-finally处理编译时异常,
finally的使用(注意点,@Test 方法不能有返回值)
1.finally是可选的
2.当catch有异常的时候、try或catch有返回值的时候finally就有必要写。
3.什么情况下才会把代码写到finally中
当数据库连接、socket、 输入输出流等jvm不能自动回收的,需要手动关闭的连接就放到finally中。(防止异常干扰连接关闭)
4.体会一:使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,不然仍然可能报错。
体会二:在开发中运行时异常通常不用try-catch处理。编译时异常使用try-catch
一个读取文件数据的代码
@Test
public void setE(){
FileInputStream fis =null;
try{
File file = new File("src/Test/hello");
fis = new FileInputStream(file);
int data = fis.read();
while (data != -1) {
System.out.println((char) data);
data = fis.read();
}
}catch(
FileNotFoundException e){
e.printStackTrace();
}catch(
IOException e)
{
e.printStackTrace();
}
finally {
try {
if (fis !=null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.异常处理机制而:throws
格式 throws + 异常类型
1.throws+异常 声明在方法得声明后,指明方法运行时可能抛出得编译异常类型,一旦方法体执行时出现异常仍然会在异常代码处生成一个异常类得对象。此对象满足throws后异常类型时,就会被抛出。异常代码后续得代码,不再执行!
2.throws 时把异常抛给调用类处理
try-catch是处理异常
3.对于解决了得编译时异常e.getstackTrace();是拿不到任何信息得,要使用e.printstackTrace。
4.父类抛出的异常必须大于等于子类的异常,当然子类可以是没有。为什么因为,测试类调用父类方法的时候如果通过多态调用到子类重写的方法就可以由于父类异常大于子类不报错。
例子:用到知识(多态,重写,异常)。
public class exce {
public static void main(String[] args) {
User user=new User();
try {
user.method(new son());
}catch (Exception e){
e.printStackTrace();
}
}
}
class User{
public void method(User user)throws Exception{
String aa ="abc";
int bb=Integer.parseInt(aa);
}
}
class son extends User{
public void method (User user)throws NullPointerException{
int arr[]=new int[10];
arr=null;
System.out.println(arr[1]);
}
}
5.开发中如何选择try-catch和throws
5.1 如果父类被重写的方法没有throws的方式处理异常,子类必须小于父类,也可以没有。这种情况对于子类的异常只能是throws。
5.2执行的方法中,先后又调用了几个方法,方法是递进关系,方法建议使用throws的方法丢给调用类处理
5.手动抛出异常:throw
一般开发者使用throw,给一些错误的运行异常或一些错误的编译异常throw出异常,当我们运行或编译踩到雷区就会把异常throw给我们,我们就要使用try-catch或throws处理,否则问题无法解决
1.throw在方法区里随意抛出任何异常给调用者完善,作用就相当于java类库的程序员对某些错误的运行或编译用throw提醒。throws在形参后面表示抛出这个方法中可能出现的某某异常,调用者需要接收该方法,对于预计到的运行异常可以直接修改代码,网络连接中断可以使用运行异常做处理,但是编译异常要解决。
代码
public class handleException {
public static void main(String[] args) {
zz z = new zz();
// try {
// z.method(-100);
// }catch (ArrayIndexOutOfBoundsException e){
// System.out.println(e.getMessage());
// }
try {
z.zz();
}catch (NullPointerException e){
System.out.println("找到问题了");
}catch (Exception e){
System.out.println("好像确定问题了");
}
}
}
class zz{
int number;
@Test
public void method(int number){
if(number>0){
this.number=number;
}else{
throw new ArrayIndexOutOfBoundsException("没找到你的对象");
}
}
public void zz()throws NullPointerException{
int k[] =new int[10];
k =null;
System.out.println(k[0]);
}
}
6.用户自定义异常类
如何自定义异常类
1.继承一个异常结构
2.定义一个全局静态常量
3.复制父类的构造器
public class MyException extends Exception {
static final long serialVersionUID = -7034897190745766939L;
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
}
总结:
1.对于异常来说主要分为运行时异常(RuntimeException)和编译时异常,他们有共同的父类Exception。
2.对于处理运行时异常如:NullpointException、ArraysIndexOutOfBoud、ClassCastExceptin、InputMissMatchException、NumberformateException、
MathmaticException、
不需要完善代码可编译输出可以不做异常处理,直接修改代码。
对于处理编译时异常如filenotfindException、IOException之类要么改代码,要么抛出异常解决。
3.手动抛出1的异常、和用户自定义异常同理,如果手动抛出的异常是exception那么调用方法的对象必须处理异常方法否则报错(因为Exception可能是编译异常。)如果自定义的异常是直接继承exception类,也是要处理异常。
4.Finally是在程序运行时一旦出现异常直接跳到Finally,再到异常处理结果
复习
练习:接收两个值用String 然后转换int 判断是否小于0如果有一个小于零就自定义一个异常类提示,另外加入其他可能的异常处理
public class EcmDef {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入您要计算的第一个数");
String a = scanner.next();
System.out.println("请输入您要计算的第二个数");
String b = scanner.next();
ff f = new ff();
try {
int A = Integer.parseInt(a);
int B = Integer.parseInt(b);
f.ecm(A, B);
} catch (InputMismatchException e) {
System.out.println("您输入的数据异常");
} catch (ArithmeticException e) {
System.out.println("您输入的除数有误");
} catch (NumberFormatException e) {
System.out.println("您输入的数据有误");
}catch (ecm e){
System.out.println(e.getMessage());
}
}
}
class ff {
public int ecm(int A, int B) throws ecm{
if (A < 0 || B < 0) {
throw new ecm("请输入正数哦"); //这里需要抛出异常对象给调用类解决,
如果写在调用类中也可以
}
return A/B;
}
}
复习
异常和错误的区别
错误:堆溢出,栈溢出,一种只能通过修改代码的解决的问题。
异常:分为运行时异常(RuntimeException)和编译时异常父类都是Exception,也就是说当异常是Exception时包括了编译时异常必须要完善代码才行运行。
可以通过处理解决(catch-throws/throw)空指针异常、数组角标越界、数据转换异常(NumberformateException)、类型转换异常(classcastException)、ArchmaticException(数值计算异常)。