您的位置:首页 > 编程语言 > Java开发

Java拾遗-异常

2015-09-03 13:53 477 查看
一、为什么需要异常

/* 示例1 */
import java.util.*;
public class TestInput {
public static void main(String[] args) {
Scanner sc = null;
try {
sc = new Scanner(System.in);
int i = sc.nextInt();
System.out.printf("%d\n", i);
} catch (InputMismatchException e) {
System.out.println("读取错误,程序终止");
}
}
}

/* 示例2 */
class A
{
int divide(int a, int b)
{
return a / b;
}

int add(int a, int b)
{
return a + b;
}
}

class Excep_1
{
public static void main(String[] args)
{
A aa = new A();
try
{
int i = aa.divide(3, 0);
System.out.println(i);
}
catch (ArithmeticException e)
{
System.out.println("除数不能为零!");
}

int j = aa.add(2, 4);
System.out.println("j = " + j);
}
}


二、什么是异常

异常(Exception)是程序运行过程中发生的事件,该事件可以中断程序指令的正常执行流程。

三、异常的处理机制

1. 当Java程序运行时出现问题时,系统会自动检测到该错误,并立即生成一个与该错误对应的异常现象。

2. 然后把该异常对象交给Java虚拟机。

3. Java虚拟机会自动寻找相应的代码处理这个异常,如果没有找到,则程序终止。

4. 程序员可以自己编写代码来捕捉可能出现的异常,并编写代码来处理相应的异常。

四、常见的一些异常

1. 空指针异常

class Person{
public int age;
}
public class TestNullPointerException{
public static void main(String[] args) {
Person p = null;
System.out.println(p.age);
}
}
/* 输出结果 */
Exception in thread "main" java.lang.NullPointerException
at TestNullPointerException.main(TestNullPointerException.java:7)


2.下标越界异常

public class TestIndexOutOf{
public static void main(String[] args) {
String friends[]={"Lisa","Bily","Kessy"};
for(int i=0;i<5;i++)  {
System.out.println(friends[i]);
}
System.out.println("\nthis is the end");
}
}
/* 输出结果 */
Lisa
Bily
Kessy
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at TestIndexOutOf.main(TestIndexOutOf.java:5)


3.算术异常

五. 异常的分类





六. 异常的处理步骤

try {
// 可能出现异常的代码块
}
catch (ExceptionName1 e) {
// 当产生ExceptionName1异常时的处理措施
}
catch (ExceptionName2 e) {
// 当产生ExceptionName2异常时的处理措施
}
....
finally {
// 无论是否捕捉到异常都必须处理的代码
}




七. finally的作用

1. 无论try所指定的程序块中是否跑出异常,也无论catch语句的异常类型是否与所抛出的异常类型一致,finally中的代码一定会执行。

2. finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分之前,能够对程序的状态统一的管理。

3. 通常在finally语句中可以 进行资源的清除工作,如关闭打开的文件,删除临时文件等。

import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;

public class ChatServer
{
public static void main(String[] args)
{
boolean started = false;
// 判断服务器是否启动了,先假定没有启动
ServerSocket ss = null;
DataInputStream dis = null;

try
{
ss = new ServerSocket(8888);
// 服务器已经启动了,设置started为true
while (started)
{ //当服务器端启动时。。。。
boolean bConnect = false;
//判断服务器和客户端的连接是否已经建立, 没有为false,连接成功返回true
Socket s = ss.accept();
//accept()与readUTF()方法一样,都是一个阻塞式方法,如果没有收到连接请求,则一直等待。。。。。
bConnect = true;  //连接成功,设置bConnect为true
System.out.println("一个连接已经建立!"); // --------------------------
dis = new DataInputStream(s.getInputStream());
while (bConnect)
{
String str = null;
str = dis.readUTF();
//如果客户端突然断开连接,该语句就会抛出异常EOFException,所以我们必须得对dis.readUTF();进行异常处理
//readUTF()是阻塞式方法,如果得不到数据,则继续等待,直到读取到数据为止
System.out.println("从客户端接受的数据是:" + str);
}
}
}
catch (BindException e)
{
System.out.println("端口已被占用,其使用其他端口");
System.out.println("请关闭相关程序,重新运行!");
System.exit(-1);
}
catch (EOFException  e)
{
System.out.println("客户端已经断开连接!");
}
catch (IOException e)
{
//e.printStackTrace();
System.out.println("服务器端读写错误!");
}
finally
{
try
{
if (null != ss)  //如果监听程序打开了,则关闭网络监听程序
{
ss.close();
ss = null;
}

if (null != dis)  //如果输入流打开了,则关闭输入流
{
dis.close();
dis = null;
}
}
catch (Exception e)
{
}
}
}
}


八. throw

1. throw用来抛出异常

2. 格式:

throw new 异常名(参数);

3. 假设f方法抛出了A异常,则f方法有两种方式来处理A异常

1. throws A

谁调用f方法,谁处理A异常,f方法本书不处理A异常

2. try{…} catch() {……}

f方法本身自己来处理A异常

4. 要抛出的异常,必须是Throwable的子类



九. throws

1. void f() throws A

{

……

}

2. throws A表示调用f方法时f方法可能会抛出A类异常,建议您调用f方法时最好对f方法可能抛出的A类异常进行捕捉。

3. throws A不表示f方法一定会抛出异常。

throws A, f方法也可以不抛出异常

4. throws A 不表示调用f方法时,必须对A异常进行捕捉

假设A是RuntimeException子类异常

由于RuntimeException的子类异常可以处理也可以不处理,所以编译器允许你调用f方法时,对f方法抛出的RuntimeException之类异常不进行处理。

5. 建议:

对throws出的所有异常进行处理

如果一个方法内部已经对A异常进行了处理,则不要再throws A



十. 注意问题

1. 所有的catch只能有一个执行

2. 所有的catch可能都没有执行

3. 先catch子类异常再catch父类异常

如果先catch父类异常,再catch子类异常,编译时报错

4. catch与catch之间不能有其他代码

5. 重写方法抛出异常的范围 不能大于重写方法抛出的异常范围

6. 编译器认为放在try里边的代码都有执行失败的可能。

/*
子类覆盖了基类方法时,
子类方法抛出异常的范围不能大于基类方法抛出的异常范围
子类方法可以不抛出异常,也可以只抛出基类方法的部分异常
但不可以抛出基类方法以外的异常
*/

//自定义异常A
class A extends Exception
{
}

//自定义异常B
class B extends Exception
{
}

//自定义异常C
class C extends Exception
{
}

class M
{
void f() throws A, B
{
}
}

class N extends M
{
void f() throws A,B
//可以throws A或B,也可以throws A,B  也可以不throws,
//但不可以throws C  即"子类覆盖了基类方法时,子类方法抛出异常的范围不能大于基类方法抛出的异常范围"
{
}
}

class Test
{
public static void main(String[] args)
{
M m = new M();
N n = new N();

System.out.println("1111");
}
}
/*
在JDK 1.6中的运行结果是:
--------------------------
1111
--------------------------
*/


/*
先catch子类异常再catch父类异常
如果先catch父类异常再catch子类异常,则编译时会报错
*/

class A extends Exception
{
}

class B extends A
{
}

class C extends B
{
}

class M
{
public void compare(int i, int j) throws A,B
{
if (i > j)
throw new A();
else
throw new B();
}
}

public class TestTryCatch
{
public static void main(String[] args)
{
M mm = new M();
try
{
mm.compare(-4, 1);
}
catch (B bb)
{
System.out.println("左边不能小于右边");
}
catch (A aa)
{
System.out.println("左边不能大于右边");
}
}
}


class A{
public void static main(String[] args)
{
int m ;
try{
m = 2;
}
catch {

}
System.out.printf("m = %d", m);
}
}
/*
编译报错,编译器认为m未初始化。
因为编译器认为try中的代码有执行失败的可能。
*/


十一. _printStackTrace方法

public A{
int divide(int a, int b)
{
return a / b;
}
public void f() {
g();
}
public void g(){
divide(6, 0);
}
}
public class Test
{
public static void main(String[] args)
{
try{
new A.f();
}
catch (Exception e){
e.printStackTrace();
}
}
}


/*
Exception类中有一个private的Message属性,通过构造函数
public Exception(String message)
可以完成对该属性的初始化

*/

class E extends Exception
{
public E()
{
super("哈哈");  //这实际是调用父类Exception的构造函数: public Exception(String message)
//this.Message = "哈哈";  //error
}
}

class M
{
public static void f() throws E  //也可以改为 throws Exception
{
throw new E();
}

public static void main(String[] args)
{
try
{
f();
}
catch (Exception e)
{
String strExcep = e.getMessage();
System.out.println("strExcep = " + strExcep);
}

System.out.println("程序正常终止了!");
}
}
/*
在JDK 1.6中的运行结果是:
--------------------------------
strExcep = 生命在于静止!
程序正常终止了!
--------------------------------
总结:
getMessage() 返回的是异常的具体信息,是个String类型
public Exception(String message) 用message字符串来表示异常的具体信息

*/


/*
自定义异常
*/

class DivisorIsMinusException extends Exception
{
public DivisorIsMinusException(String message)
{
super(message); //实际是调用Exception 的构造函数 public Exception(String message)
}
}

class HH
{
public void f(int a, int b) throws DivisorIsMinusException
{
if (b < 0)
throw new DivisorIsMinusException("除数不能为负数!");
}
}

class Excep_3
{
public static void main(String[] args)
{
HH h = new HH();
try
{
h.f(3, -2);
}
catch (DivisorIsMinusException e)
{
System.out.println(e.getMessage());
}
System.out.println("程序正常终止了!");
}
}
/*
在JDK 1.6中的运行结果是:
--------------------------
除数不能为负数!
程序正常终止了!
--------------------------
*/


十二. 异常的优点

1. 没有错误处理的程序:

{

openTheFile;

determine its size;

allocate that much memory;

read-file;

closeTheFile;

}

/* 以常规方法处理错误 */
openFiles;
if (theFileOpen)
{
determine the length of the file;
if (gotTheFileLength) {
allocate that much memory;
if (gotEnoughMemory)
{
read the file into memory;
if (readFileFailed)
errorCode = -1;
else
errorCode = -2;
}
else errCode = -3;
}
else errorCode = -4;
}
else errorCode = -5;




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: