黑马程序员——Java基础—异常、package

时间:2021-07-31 12:56:09

Java基础之异常、package


异常:就是程序在运行时出现不正常的情况。

异常的由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述并封装成对象。

其实就是java对不正常情况进行描述后的对象体现。

问题划分为两种:

一种是严重的问题,java通过Error类进行描述。对于Error一般不编写针对性的代码对其进行处理。

一种是非严重的问题,java通过Exception类进行描述。对于Exception可以使用针对性的处理方式进行处理。

无论是Error或是Exception都具有一些共性内容。 Error和Exception的子类名都是以父类名作为后缀。

它们的父类都是Throwable类。

异常的处理:java提供了特有的语句对异常进行处理。 

try{ 需要被检测的代码 }   catch(异常类 变量){ 处理异常的代码(处理方式) }  finally{ 一定要执行的语句 } 这三个是一个整体。

getMessage()通过这个方法可以获取异常信息。 

toString() 这个方法能看到异常名称+异常信息。

printStackTrace() 异常名称,异常信息,异常出现的位置。

其实JVM默认的异常处理机制就是在调用printStackTrace()方法打印异常的堆栈的跟踪信息。

throws Exception :在功能上通过throws关键字声明了该功能有可能会出现问题。

在函数上声明异常提高了安全性,让调用者进行处理否则会编译失败。

当问题抛给主函数的时候,主函数就不要再向上抛给虚拟机了。主函数要提供解决问题的方式。也就是try{}  catch(){}

异常处理示例:

class Demo
{
int div(int a, int b)throws Exception //在功能上通过throws关键字声明了该功能有可能会出现问题
{
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d = new Demo();
try
{
int x = d.div(5,0);
System.out.println("x="+x);
}
catch (Exception e)
{
System.out.println(e.getMessage()); //getMessage()通过这个方法可以获取异常信息。
System.out.println(e.toString()); //toString() 这个方法能获取异常名称+异常信息。
e.printStackTrace(); //printStackTrace() 异常名称,异常信息,异常出现的位置。
//其实JVM默认的异常处理机制就是在调用printStackTrace()方法打印异常的堆栈的跟踪信息。
}
System.out.println("over");
}
}

多异常处理:

1.声明异常时建议声明更为具体的异常,这样可以处理的更具体。  

2.对方声明几个异常就对应几个catch块,不要定义多余的catch块。如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。 
建议在进行catch处理时,catch中一定要定义具体的处理方式,不要简单的写一条输出语句。

代码演示:

class Demo
{
//在功能上通过throws的关键字声明了该功能有可能会出现问题。
int div(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException
{
int[] arr = new int[a];

System.out.println(arr[4]);

return a/b;
}
}
class ExceptionDemo2
{
public static void main(String[] args) //throws Exception
{
Demo d = new Demo();
try
{
int x = d.div(5,0);
System.out.println("x="+x);
}
catch (ArithmeticException e)
{
System.out.println(e.toString());
System.out.println("被零除了!!");

}
catch (ArrayIndexOutOfBoundsException e)
{
System.out.println(e.toString());
System.out.println("角标越界啦!!");
}
catch(Exception e)
{
System.out.println("hahah:"+e.toString());
}
System.out.println("over");
}
}

自定义异常:

在项目中会出现特有的问题,而这些问题并未被java所描述并封装对象,所以对于这些特有的问题可以按照java对问题封装的思想,将程序中出现的特有问题进行自定义的异常封装。

当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。要么在内部try catch处理,要么在函数上声明让调用者处理。一般情况,在函数内出现异常,需要在函数上声明。

如何定义异常信息呢 ?
因为父类中已经把异常信息的操作都完成了,所以子类只要在构造时将异常信息通过super语句传递给父类就可以直接通过getMessage方法获取自定义的异常信息。
自定义异常时,自定义类必须继承Exception类,因为异常体系有一个特点:异常类和异常对象都具有可抛性,而这个可抛性是Throwable这个体系中独有的特点。只有这个体系中的类和对象才可以被throws和throw操作。

自定义异常代码:

class FuShuException extends Exception  //继承Exception类。
{
private int value;

FuShuException()
{
super();
}
FuShuException(String msg,int value)
{
super(msg);
this.value = value;
}
public int getValue()
{
return value;
}
}


throws和throw的区别:

throws使用在函数上,后面跟的是异常类,可以跟多个用逗号隔开。

throw使用在函数内,后面跟的是异常对象,throw单独存在时下面不可以定义语句,因为执行不到。

Exception中有一个特殊的子类异常RuntimeException,运行时异常。如果在函数内抛出该异常,函数上可以不用声明,编译可以通过。如果在函数上声明了该异常,调用者可以不用进行处理,编译可以通过。之所以不用在函数声明是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时。出现了无法继续运算的情况,希望停止程序后对代码进行修正。  运行时异常示例:

class FuShuException extends RuntimeException
{
FuShuException(String msg)
{
super(msg);
}
}
class Demo
{
int div(int a,int b)throws Exception//throws ArithmeticException
{
if(b<0)
throw new Exception("出现了除数为负数了");
if(b==0)
throw new ArithmeticException("被零除啦");
return a/b;
}
}
class ExceptionDemo4
{
public static void main(String[] args)
{
Demo d = new Demo();

int x = d.div(4,-9);
System.out.println("x="+x);

System.out.println("over");
}
}

自定义异常时,如果该异常的发生无法继续进行运算,那么就让自定义异常继承RuntimeException。
异常分两种:1.编译时被检测的异常。该异常在编译时没有处理(既没有抛也没有cry)会编译失败。该异常被标识说明可以被处理。2.编译时不被检测的异常(运行时异常,RuntimeException以及其子类)。该异常发生建议不处理,让程序停止,对代码修正。

finally{} 语句很重要,里面写的是一定要执行的语句,(finally{}语句只有一种情况不会被执行到:在finally之前有System.exit(0)(系统退出,虚拟机结束)的时候)。通常用于关闭资源或必须要执行的代码。也可以出现有try 和finally而没有catch的情况。  catch是用于处理异常的,如果没有catch就代表异常没有被处理过,如果该异常是检测时异常,那么必须声明。 finally代码示例:

class FuShuException extends Exception
{
FuShuException(String msg)
{
super(msg);
}
}
class Demo
{
int div(int a,int b)throws FuShuException
{
if(b<0)
throw new FuShuException("除数为负数");
return a/b;
}
}
class ExceptionDemo5
{
public static void main(String[] args)
{
Demo d = new Demo();

try
{
int x = d.div(4,-1);
System.out.println("x="+x);

}
catch (FuShuException e)
{
System.out.println(e.toString());
return;
}
finally
{
System.out.println("finally");//finally中存放的是一定会被执行的代码。
}
System.out.println("over");
}
}

异常在子父类中的体现(覆盖时的异常特点):

1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者父类异常的子类。

2.如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。

3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时也不可以抛出异常。如果子类方法发生了异常就必须进行cry处理,绝对不能抛。

class AException extends Exception
{
}
class BException extends AException
{
}
class CException extends Exception
{
}
class Fu
{
void show()throws AException
{

}
}
class Test
{
void function(Fu f)
{
try
{
f.show();
}
catch (AException e)
{

}

}
}
class Zi extends Fu
{
void show()throws CException
{
}
}
class
{
public static void main(String[] args)
{
Test t = new Test();
t.function(new Zi());
}
}

异常的好处:

1.将问题进行封装。

2.将正常流程代码和问题处理代码相分离,方便于阅读。

异常的处理原则:
1.处理方式有两种:try 或者 throws。 

2.调用到抛出异常的功能时,抛出几个就处理几个。一个try可以对应多个catch。 

3.当多个catch时,父类的catch放到最下面。

4.catch内要定义针对性的处理方式,不要简单的定义成printStackTrace 或输出语句,也不要不写。

5.当捕获到的异常本功能处理不了时,可以继续在catch中抛出。

6.如果该异常处理不了,但并不属于该功能出现的异常,那么可以将异常转换后再抛出和该功能相关的异常。或者异常可以处理,当需要将异常产生后和本功能相关的问题提供出去让调用者知道并处理,也可以将捕获异常处理后转换新的异常。


包 package:

对类文件进行分类管理。给类提供多层命名空间。写在程序文件的第一行。

类名的全称是:包名.类名。包也是一种封装形式。

一个包中的类要想被访问必须要有足够大的权限,所以被访问的类要被public修饰。

类公有后,被访问的成员也要公有才可以被访问。

package代码示例:

package pack;

class PackageDemo
{
public static void main(String[] args)
{
packa.DemoA d = new packa.DemoA(); //注意:当出现包之后类名就变成:包名.类名
d.show();
//packb.DemoB d = new packb.DemoB();
//d.mehod();
}
}
package packb;public class DemoB {protected /*保护*/ void method(){System.out.println("demoB method run");}}

总结:包与包之间进行访问,被访问的包中的类以及类中的成员需要public修饰。不同包中的子类还可以直接访问父类中被protected权限修饰的成员。包与包之间可以使用的权限只有两种public和protected。

import 关键字,导入
为了简化类名的书写,使用一个关键字import 。import是导入包中的类,示例:import packb.haha.hehe.*  导入packb下的haha下的hehe下的所有的类。 "*" 是通配符,代表所有的意思。但是在实际开发中,建议不要写通配符"*",而是需要用到包中的哪个类就导入哪个类,不建议全部导入。建议定义包名时不要重复,可以使用url来完成定义,url是唯一的。

import packb.haha.hehe.heihei.*;
import packa.*;
import packb.*;
class PackageDemo
{
public static void main(String[] args)
{
DemoC c = new DemoC();

packa.DemoA d = new packa.DemoA();
d.show();
packb.DemoB d = new packb.DemoB();
d.method();
}
}