--------------------- android培训、java培训、java学习型技术博客、期待与您交流! -------------------
1 异常认识与使用
异常是java中的一种转对于可能会存在的不正常操作和运行等引起的程序错误而存在的一种机制。在java中把各种问题进行抽取,进行描述,封装成对象,供解决各种问题而使用。
异常体系:
Throwable
|----Error
*通常出现重大问题如:运行的类不存在或者内存溢出等。
*不编写针对代码对其处理
|----Exception
*在运行时运行出现的一些问题,可以通过try—catch—finally
*Exception和Error的子类名都是以父类名作为后缀。
异常的种类:
@两种:一种是严重的问题,一种是非严重的问题。
对于严重的问题,java通过Error类进行描述。
对于Error一般不编写针对性的代码对其进行处理。
对于非严重的,java 通过Exception类进行描述。
对于Exception可以使用针对性的处理方式进行处理。
@Error举例:在主函数中添加 byte[] arr=new byte[1024*1024*600];
结果:出现内存溢出错误。(Java.lang.OutOfMemoryError)
无论Error和Exception 都具有一些共性内容。
比如:不正常情况的信息,引发原因等
非严重异常:
编译时处理异常:除了RuntimeException之外的异常都是。需要编译时进行异常的抛出,或再进一步的处理。
运行时处理异常:指的是Exception中的RuntimeException 异常。发生此异常,希望程序能够停下来,编译时并不进行异常抛出和解决,如,希望修改错误代码。
异常的处理:
异常的处理是最为重要的,其存在的目的就是进行异常的处理。如果在编译时只出现了异常,说明是程序的最后一步,因为,在报出异常之前java会把所有句法错误 等进行报出。为了使程序能够在出现异常后继续运行后面的程序,就需要进行异常的处理。
使用throws进行抛出:将存在的异常抛给调用者,谁调用了抛出异常的方法就抛给谁。 这种方法是简单的处理方式也是不推荐使用的。在main方法上进行抛出异常,就将异常抛给了JVM,异常时程序将不能继续运行。正常情况下,调用者要对抛出的异常进行有效的处理,即使用try-catch块处理。
使用try-catch进行处理:
其处理的完整格式为:
try
{
//可能出现异常的程序,被检测的代码
}
catch(//捕获的异常对象)
{
//异常信息输出,对异常的处理
}
finally
{
//最终必须执行的程序
}
这是其中的一种格式,还有两种:
其1:
try{}catch(){}
其2:
Try{}finally{}
例子:
class Demo
{
int div(int a,int b)
{
return a/b;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
try
{
int x=d.div(4, 0);
System.out.println("x="+x);
}
catch(Exception e)
{
System.out.println("除零啦");
System.out.println(e.getMessage());// by zero
System.out.println(e.toString());//异常名称:异常信息
e.printStackTrace();//异常名称,异常信息,异常出现的位置
//其实jvm默认的异常处理机制,就是在调用PrintStrackTrace方法
//打印异常的堆栈的跟踪信息。
}
System.out.println("over");
}
异常问题:
@判断下面的代码能否编译通过?
class
{
public void method()//此处应该进行异常的抛出 throws Exception
{
throw new Exception();
}
}
答案:通过不了,因为函数内部有异常,需要在函数上面抛出异常才能编译通过。
@另一题:
class
{
public void method()
{
try
{
throw new Exception();
}
catch (Exception e) { }
}
}
上面的编译呢?
答案是能通过,原则是只要问题被解决,try中不管有没有问题,都直接抛出异常了,只要解决了问题,就可以编译通过,就不用函数声明。
@问题解决:有catch就是问题解决么?
class
{
public void method()
{
try
{
throw new Exception();
}
catch (Exception e)
{
throw e;
}
}
}
上面的代码编译失败,原因:抓到了一个问题,抛给了catch,但是catch又抛出了,没有解决问题。
@另一题:
class
{
public void method()
{
try
{
throw new Exception();
}
catch (Exception e)
{
try
{
throw e;
}
catch ()
{
}
}
}
}
上面的代码能编译通过,原因是只要抛出的问题,被try了,问题被处理就可以编译通过。并没有再次抛出异常,只是没有处理语句。
@另一题:
class Demo
{
public void method()
{
try
{
throw new Exception();
}
catch (Exception e)// throwsException
{
try
{
throw e;
}
finally
{
//关闭资源
}
}
}
}
编译不会通过,因为没有catch()语句,捕捉到异常没有被处理,没有catch就没处理,只能在函数上标示出去才能编译通过.finally中的语句一般都是关闭资源的语句。不管有没有异常,finally内部的语句都会执行,所以一般写入必须执行的代码写到里面,用来关闭资源
Catch就是用来处理异常的,没有catch就代表异常没有处理过,如果该异常是检测时异常,那么必须在函数上进行声明
多个异常处理:
在声明异常时,建议声明更为具体的异常,这样可以更好的帮助解决问题,不同的问题返回不同的处理信息,可以更友好的发现问题。
例子:
class Demo
{
int div(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException
{
int[] arr =new int[a]; System.out.println(arr[4]); 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(ArithmeticException e)
{
System.out.println(e.toString());
System.out.println("被零除了!!");
}
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println(e.toString());
System.out.println("角标越界啦!!");
}
System.out.println("over");
}
}
异常的继承:
1、 子类在覆盖父类时,如果父类的方法抛出异常,那么子类的方法只能抛出父类的异常,或者该异常的子类(或者不抛)
举例Exception
|--AException
|--BException
|--CException
如果父类抛出了AException,子类继承了父类,那么子类只能抛出AException或者BException不能抛出CException
演示代码:
classAException extends Exception
{
}
class BException extends AException
{
}
class CException extends Exception
{
}
class Fu
{
voidshow()throws AException
{
}
}
class Test
{
voidfunction(Fu f)
{
try
{
f.show();
}
catch(AException e)
{
}
}
}
class Zi extends Fu
{
voidshow()throws CException
{
}
}
class
{
publicstatic void main(String[] args)
{
Testt = new Test();//建立对象t
t.function(newZi());//执行对象t中function,function的接收对象为fu类对象,new Zi()是在运用多态
}//上条代码分成两个就是Fu f=new Zi();t.function(f);当调用子类对象的时候,如果抛出的是c异常,父类捕捉的是a异常,父类只能捕捉a异常以及其子类异常。所以子类抛c异常会捕捉不到
}
2、 如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
如父类抛出ABCDE异常,子类只能抛出ABC BC DE AE等子集异常,原则就是子类抛的异常父类能处理就行
3、 如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法发生了异常。就必须要进行try处理。绝对不能抛。
异常练习
异常的好处就是将源代码处理流程和出现的问题相分离,将异常封装成对象,方便解决问题。
例子:
classNoValueException extends RuntimeException//继承RuntimeException的意义就是当这个NoValueException出现问题时,涉及到了程序已经无法运行,需要停下来程序进行修正,那么就继承RuntimeException
{//RuntimeException的继承就是代表如果这个异常出现问题,程序就停止
NoValueException (String message)
{
super(message);//调用父类中的方法,直接返回接受的message
}
}
interfaceShape//求面积的父类接口
{
void getArea();
}
class Recimplements Shape //长方形面积,继承父类接口
{
private int len,wid;
Rec(int len , int wid)//throwsNoValueException
{//当继承的是RuntimeException时,函数上面就不用声明了。如果没有继承RuntimeException而是继承别的异常,函数内部有异常抛出,函数上面必须声明
if (len<=0 || wid<=0)//如果长和宽有一个小于等于0,那么就抛出异常
throw newNoValueException("出现非法值");//抛给NoValueException,如果此时NoValueException没有继承RuntimeException,那么必须在函数上面进行声明
this.len = len;
this.wid = wid;
}
public void getArea()
{
System.out.println(len*wid);//获取面积
}
}
class Circleimplements Shape
{
private int radius;
public static final double PI=3.14;//全局常量,权限够大,不需要对象就能访问,一般都是这种pi的特殊固定值
//记住这个格式,public static final ,全部常量,权限很大,不需要对象就可以访问,用这个格式
Circle (int radius)
{
if (radius<=0)//如果圆半径小于等于0,抛出异常
throw newNoValueException("非法值");//这里可以抛给RuntimeException,但是最好还是抛给NoValueException,因为这个异常是我们编写的自定义异常,抛给这个异常如果有错误那么输出的时候会显示这个具体的异常,方便得知哪里有异常
this.radius = radius;
}
public void getArea()
{
System.out.println(radius*radius*PI);
}
}
classExceptionTest1
{
public static void main(String[] args)
{ /*如果异常继承了RuntimeException,那么在主函数内部就不用try了,因为遇到异常后会直接停止程序,并自动输出异常信息。如果上面的函数有声明,这里必须进行try必须进行处理。
try//异常处理的好处,就是将正常代码放在try里面,阅读时可以只看try内的代码就知道怎么运行程序了。
{
Rec r =new Rec(-3,4);
r.getArea();
}
catch (NoValueException e)//而如果有议程需要处理的问题,就放在catch里面,这样实现了将问题封装分离,方便阅读已经编写代码
{
System.out.println(e.toString());
}
System.out.println("程序结束");
*/
Rec r =new Rec(3,4);
r.getArea();
Circle c = new Circle (-8);
System.out.println("程序结束");
}
}
2 自定义异常
Java中定义好的异常类可能满足不了一些开发问题,对于一些特殊的问题需要有特殊的异常类进行处理,java的异常类库中提供的异常类不能满足需求,这时就需要开发者自定义异常类,供开发使用。
自定义异常过程:
定义异常类,继承自Exception或其子类。
class MyException extends Exception
{
//构造方法
MyException(String message)
{
//使用父类中的构造方法
super(message);
}
}
//定义一个可能出现异常的类
class Test
{
public static void main(String[] args)
{
//处理异常
try
{
method();
}
catch(MyException me)
{
System.out.println(“出现异常!”);
}
}
public static void method() throws MyException
{
System.out.println(“测试方法”);
Throw new MyException(“”);
}
}
下面是一个除数不允许为负数的例子,在除数为负数时抛出异常。
classFuShuException extends Exception
{
FuShuException(String msg)
{
super(msg);
}
}
class Demo
{
int div(int a ,int b)throwsFuShuException//throws后面的是类
{
if (b<0)
throw new FuShuException("除数小于零");//throw后跟的是异常对象,这个异常对象一般用匿名引用,并且符合构造函数。内部有字符串符合上面写的构造函数,不写编译不通过,要按照构造函数的格式写抛出对象
return a/b;
}
}
class ExceptionDemo55
{
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;//return的意思就是结束程序,如果有这个代码,那么最后一句over就不会输出,只有catch到异常,那么就直接处理异常,调用finally。
}//return的意义就是遇到异常就结束主函数
finally
{//finally内部存放的是一定会被执行的语句,无论有没有异常被捕捉,都会被执行
System.out.println("最后必须输出的语句");
}
System.out.println("over");
}
}
自定义异常小结:在自定义异常时:如果该异常的发生,无法再继续进行运算,就让自定义异常继承RuntimeException。
自定义异常使用顺序:
1 定义用到的异常类
2 在相应方法上 throws 对象的异常类
3 在方法内 throw 方法上抛出的异常类的异常对象
-------注意:
4 在调用抛出异常的方法时,要记得相应的在方法内抛出相应异常对象
5 在一个抛出异常的方法内调用另一个抛出异常的方法,要把调用的方法写在try内,并catch相应的异常对象。
异常常见问题:
throws 和 throw的区别?
答:1.throws使用在函数上,throw使用在函数内。
2.throws后面跟的异常类可以跟多个,用逗号隔开。throw后面的是异常对象。
注意:Exception 中有一个特殊的异常,RuntimeException 运行时异常。如果在函数
内容抛出该异常,函数上可以不声明,编译一样通过。如果在如果在函数上声明了该 异
常。调用者可以不进行处理,编译一样通过。
之所以不用在函数上声明,是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后由程序员对代码进行修正。
下面的函数是编译运行都正常,但是ArithmeticException改成Exception编译就出错了,
这里是因为ArithmeticException是RuntimeException 的子类。
例1:
classFuShuException extends Exception
{
FuShuException(String msg)
{
super(msg);
}
}
class Demo
{
int div(int a ,int b)throwsFuShuException//throws后面的是类
{
if (b<0)
throw new FuShuException("除数小于零");//throw后跟的是异常对象,这个异常对象一般用匿名引用,并且符合构造函数。内部有字符串符合上面写的构造函数,不写编译不通过,要按照构造函数的格式写抛出对象
return a/b;
}
}
class ExceptionDemo55
{
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;//return的意思就是结束程序,如果有这个代码,那么最后一句over就不会输出,只有catch到异常,那么就直接处理异常,调用finally。
}//return的意义就是遇到异常就结束主函数
finally
{//finally内部存放的是一定会被执行的语句,无论有没有异常被捕捉,都会被执行
System.out.println("最后必须输出的语句");
}
System.out.println("over");
}
}
该函数编译可以通过,但是运行不能通过。
对于异常分为两种:
1.编译时被检测出异常。(方法内有编译时异常throw则要在方法上throws,有throws就要在调用方法是 try-catch 或继续抛出)
2.编译时被不被检测的异常(运行时异常,RuntimeException以及其子类)
Java中常见的几种异常:
算术异常类:ArithmeticExecption
空指针异常类:NullPointerException
类型强制转换异常:ClassCastException
数组负下标异常:NegativeArrayException
数组下标越界异常:ArrayIndexOutOfBoundsException
违背安全原则异常:SecturityException
文件已结束异常:EOFException
文件未找到异常:FileNotFoundException
字符串转换为数字异常:NumberFormatException
操作数据库异常:SQLException
输入输出异常:IOException
方法未找到异常:NoSuchMethodException
异常总结:
异常:
|-- 在程序运行中,出现的不正常现象
|-- 在java中,异常体系
最高类父类是 Throwable
|-- Exception 所有异常的父类 小病小灾
异常是处理后,程序还可以继续运行
|-- Error 所有错误的父类 -- 艾滋,癌症
处理不了,必须修改代码
|-- Throwabel中的3个最常用方法
|-- String getMessage() 返回此 throwable 的详细消息字符串。
/ by zero
|-- void printStackTrace() 将此 throwable 及其追踪输出至标准错误流
java.lang.ArithmeticException: / by zero
at Div.div(ExceptionDemo.java:21)
at ExceptionDemo.main(ExceptionDemo.java:33)
|-- String toString() 返回此 throwable 的简短描述。
java.lang.ArithmeticException: / by zero
演示异常三个方法的时候,思考一个问题:虚拟机默认调用的是哪个方法 printStackTrace
7. java中第一种异常处理方式
try
{
可能出现异常的代码
被检测的代码
}
catch(异常类 变量)
{
异常的处理代码
}
8.java中第二种处理方式 throws方式
函数内手动抛出异常 用 throw关键字
函数声明上,标明抛出异常 throws关键字
调用者要么try catch 处理,要么继续抛出
9.java中异常分成两种状态
|-- 编译时期异常
|-- 调用了抛异常的方法,调用者,try 选择 继续抛
|-- 运行时异常
|-- 编译成功,运行时发生异常
|-- 运行时期异常,有一个父类 RuntimeExcepton
和他的所有子类,都被称为运行时异常对象
数组越界 空指针 类型转换异常
|-- 运行时期异常,有一个最大特点,方法中抛出异常,方法声明上可以不声明出来
调用者可以不用处理这个运行时异常
抛出运行时期异常的目的在于,程序必须停下来,不能再运行了,修改代码
10. 自定义异常
|-- java中所有的异常,不是都已经封装成对象
我们需要自定义异常,来实现java语言中没有描述异常的对象
|-- 定义一个类,继承Exception,我们这个类才是异常类,具备可抛性
|-- 手动写构造方法,将异常消息传递给父类
11.throw 和 throws的区别
|-- throw 手动抛出异常对象,后面跟对的是异常对象
|-- throw 作用在函数中
|-- throws 后面跟的是异常类,定义在方法的声明上
12.try catch finally
|-- finally 中的代码一定要执行,一般用于关闭资源使用
3 包
|--程序内使用包
|--声明创建包: package 包名;
|--生成包命令
|--在当前目录下生成:javac -d . Test.java---> "." 代表当前目录
|--在制定目录生成:javac -d E:\JavaTest Test.java
意思是在什么位置生成这个类的文件,也能说明包是用来存放类的。把编译之后的.class文件存放到指定目录下。命令将自动生成文件目录,即包名目录。
不同包之间的类相互使用:要注意class 和 方法、构造方法的权限。
1--权限足够大
2--类要写全名,加上所在的包名
注意1:
(1)package 语句必须放在源文件的最前面,除了空行和注释,其之前不可以有任何语句
(2)每个源文件中最多有一句package语句,因为一个类不可能属于两个包,如同 不能把 一件衣服放进两个箱子一样。
(3)包名可以是用"."分割的一个序列,如java.lang,表明此源文件在java.下的lang包中
|--导入包: import <包名>.类名;
import <包名>.*;//* 为通配符
注意2:
在java.util和java.sql中都有Date 类,怎么用呢?!
import java.util.*;
import java.sql.*;
Date d=new Date();
这样用是错误的,系统不知道用的是哪一个包中的Date类
import java.util.*;
import java.util.Date;
import java.sql.*;
再 Date d=new Date();
就不会报错,系统会优先考虑使用明确了
这样的话就不会报错了。 很多人会问,不是导入util包了么,为什么还要再导入Date累呢?
原因就在这里,明确后 会取得优先级。
若两个包中的Date类都要使用就需要加上包名了。
如:java.sql.Date d=new java.sql.Date();
jar 压缩包:
方便携带,不需要解压缩。
里面都是class文件。
jar 常用命令:
-c 创建新的归档文件
-x 解压缩已归档的文件
-v 在标准输出中生成详细输出
-f 指定归档文件
组合使用1: -cvf
组合使用2: -xvf
静态导入:
import static <包>.<类>.*;
import static <包>.<类>.<集体方法/成员变量>;
使用方法和导入 类 类似。
import static java.lang.System.*;//导入System下的静态方法和静态成员;
直接使用: out.println();//使用简单化;
静态引用并不多用,容易降低易读性,造成维护困难。
用处:
(1)算术运算
对Math类使用静态引入,就可以更加自然,只写方法名:Math.abs()
(2)静态常量
若使用带有大量繁琐名字的静态常量,使用静态导入非常好。
3 访问控制
类的访问控制:
类A访问类B时:三种情况
。在类A中创建类B的对象
。使用类B中的某些方法 和 成员变量
。继承类B
类之间的访问主要依赖于 访问权限,简单地说就是可见性。即 类的访问控制。
public
default :不加访问说明符时的权限,默认权限
final :最终类,不能被继承
abstract :抽象类
方法的访问控制:
public 同类 同包 子类 通用性
protected 同类 同包 子类
default:(不加访问控制符) 同类 同包
private 同类
方法其他修饰符:
static :只能修饰成员,变量、方法、语句块,内部类等。
使用情况:1 直接用类名引用成员 2 需要记录对象的个数等关于对象的信息 时
final:为了确保类中的方法在继承过程中 保持不变化,当方法很小,不希望被覆盖 (override)时用final,class中所有的private和static自然就是final。
Abstract:抽象。
native:值在java中可以使用但不可以编写的方法。是java和本地应用程序之间的中介。
synchronized:同步的,在多线程中运用。
本篇博文结束!
@感谢老师的辛苦批阅