黑马程序员技术交流社区

标题: 深入剖析异常问题? [打印本页]

作者: 蔡园园    时间: 2011-9-20 18:39
标题: 深入剖析异常问题?
先贴出我的代码再引出我的问题[code=java]package cn.itcast.heima;
import javax.servlet.GenericServlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloGeneric extends GenericServlet{
        public void service(ServletRequest req,ServletResponse res){
                try{
                        PrintWriter pw = res.getWriter();
                         pw.println("你好,我是GenericServlet!");
                }catch(ServletException e){
                        e.printStackTrace();
                }catch(IOException e){
                        System.out.println(e.toString());
                }
        }
}[/code]我们知道要编写一个Servlet程序,有三种方法,我采用其中一种是继承GenericServlet抽象类,其中只有Service是抽象方法,所以采用这种方式必须复写Service方法,但是我们查下Servlet文档可知完整定义是这样的public abstract void service(ServletRequest req,ServletResponse res)throws ServletException,java.io.IOException,这是要抛出两个异常的,一个ServletException,一个IOException。
而我的疑问一、是复写方法可以不采用这种定义方式[code=java]public void service(ServletRequest req,ServletResponse res)throws ServletException,java.io.IOException{代码块}[/code]而可以采用在复写方法时直接try catch住异常,如我上面写法,这是为什么?
疑问二、其实我上面写法有点错误。
上面不能捕获ServletException错误,否则编译出现错误。
错误:HelloGeneric.java:13: 错误: 在相应的 try 语句主体中不能抛出异常错误ServletExcept
    ion}catch(ServletException e){
     1 个错误

为什么方法会抛出ServletException错误,但为什么不能捕捉呢?
而这样写却通过了
正确代码:[code=java]package cn.itcast.heima;
import javax.servlet.GenericServlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloGeneric extends GenericServlet{
        public void service(ServletRequest req,ServletResponse res){
                try{
                        PrintWriter pw = res.getWriter();
                    pw.println("你好,我是GenericServlet!");
                }catch(IOException e){
                        System.out.println(e.toString());
                }
        }
}[/code]在tomcat运行该程序,正确执行,然而却被上面两个疑问给难住了,期待童鞋们的解答!!!!!!!!
[ 本帖最后由 蔡园园 于 2011-09-20  18:40 编辑 ]
作者: 匿名    时间: 2011-9-20 21:55
疑问一:
         因为异常是谁调用谁处理的,当然你可以在重写的方法中进行异常处理。

疑问二:
       子类重写父类的方法,应该抛出比父类方法更少的异常,按你那种想法是正确的,但是ServletException是由tomcat之类的服务器处理的异常,JVM无法进行处理,所以不能进行catch
作者: 李叶    时间: 2011-9-21 02:08
呵呵,简单解释下吧:

疑问一:为什么在复写service方法的时候,可以直接在子类中try catch异常而不必抛出?

在JAVA中,如果子类复写父类的方法,那么只有以下几个限制:
1、在子类中复写的方法,不允许比父类方法的访问权限更小
例如:父类有一个方法的访问权限定义成public的
那么子类复写这个方法的话,子类中该方法的访问权限就只能是public的,而不能比public更小

2、在子类中复写的方法,不允许比父类方法抛出更宽泛的CheckedException
例如:父类有一个方法抛出了IOException
如果子类复写这个方法的话,那么子类中的这个方法:
1、可以抛出其它的RuntimeException,例如NullPointerException等
2、不可以抛出其它的CheckedException,例如ClassNotFoundException等
3、可以抛出IOException的子类,例如FileNotFoundException等
4、不可以抛出IOException的父类,例如Exception等
5、可以不抛出IOException,也可以抛出IOException

所以,由于GenericServlet的service()方法中抛出了ServletException和java.io.IOException
那么你在继承GenericServlet并复写service方法时,如果直接try catch住异常的话
你的service方法就没有抛出这ServletException和java.io.IOException这两个异常
这样也是遵循第二条规范的,因此这样写也是允许的

===================================================

疑问二:为什么catch(ServletException e)的时候会出错?

其实这个问题很简单:
在JAVA中,如果你catch了某个CheckedException的话,那么在try语句块中就必须能够抛出这个异常

然后我们来看一下你这几行代码:
  1. try{
  2.   PrintWriter pw = res.getWriter();
  3.   pw.println("你好,我是GenericServlet!");
  4. } catch(IOException e) {
  5.   System.out.println(e.toString());
  6. }
复制代码
我们查询一下Servlet的API,就可以知道
ServletResponse的getWriter()方法会抛出IOException,而PrintWriter的println()是不抛出异常的
因此,在try语句块中的两行语句就只会抛出IOException,而不会抛出ServletException

所以,由于ServletException是一个CheckedException
而try语句块中的语句并没有抛出ServletException
因此,如果你在下面catch(ServletException e)的话,JAVA就会报错

当然,如果按照下面这样改的话,也是可以的
虽然这样的代码没有什么实际意义,但是应该会有助于你更好地理解上面的话~
  1. try{
  2.   PrintWriter pw = res.getWriter();
  3.   pw.println("你好,我是GenericServlet!");
  4.   throw new ServletException();    //在try语句块中主动抛出一个ServletException
  5. } catch(IOException e) {
  6.   System.out.println(e.toString());
  7. } catch(ServletException e) {      //这样的话,catch就不会报错了
  8.   System.out.println(e.toString());
  9. }
复制代码
所以,总结一下结论吧~
如果你在catch语句中捕获了某个CheckedException的话
那么你在try语句块中就必须能够抛出这个异常
而与方法是否抛出了这个异常无关

TIPS:给一个Servlet的在线API地址吧,apache官网的,你可以上去查一下~
http://tomcat.apache.org/tomcat-5.5-doc/servletapi/

[ 本帖最后由 李叶 于 2011-09-21  03:04 编辑 ]
作者: 匿名    时间: 2011-9-21 02:34
标题: 回复 藤椅 的帖子
我真不知道黑马训练营是一群什么样的人,有点发怵了:(
作者: 匿名    时间: 2011-9-21 03:07
标题: 回复 板凳 的帖子
额……不用发怵~
像我这么啰嗦的人应该属于个例,哈哈~
谁都是一点点学出来的,只要努力就好!
作者: 匿名    时间: 2011-9-21 06:50
你们都好厉害啊,我要加油了。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2