黑马程序员 Java基础<四>---> 异常

本文深入讲解Java中的异常处理机制,包括异常的概念、分类、处理方式及自定义异常等内容。通过实例演示如何有效处理异常,确保程序稳定运行。
-----------  android培训 java培训 、java学习型技术博客、期待与您交流! ------------

错误是我们人生中必不可少的一种美,是的,同时是很让人不爽的。而在java程序中也会出现这样或那样不爽的问题。如果程序中存在错误,或者由于一些外部等不良情况发生了,这就会使得用户的数据受损。所以,一个好的程序,应该尽量避免此类情况的发生,或者必须“治愈这种病”,也就是对程序的异常进行处理。所以应该做到这样几点:
1、将可能发生的错误通知给用户
2、发生错误的时候,应该讲已操作的数据进行保存其结果
3、提供给用户适当的途径结束程序。
4、程序员还需定期查看程序异常,并进行修正
一、异常概述:
1、异常是指程序在运行时出现的不正常情况
2、异常由来:问题是现实生活中的事物,也可以通过java类的形式进行描述,并封装成对象。因为异常也可以被抽取,形成一个体系,并由一个个具体的实例组成,也是一个个对象。
3、程序可能出现的错误或问题
a.用户输入错误导致的异常:如用户不正常使用程序,输入一些非法参数
b.设备硬件等发生的错误:如硬盘损坏等
c.物理限制:如存储空间不足等
d.代码错误:在程序编写的方法可能不正确,返回错误参数等。
二、异常体系:
                                            
1、异常分为两种:严重的和非严重的异常。
a.严重的异常:java通过Error类进行描述;一般不编写针对性的代码进行处理
b.非严重异常:java通过Exception类进行描述,可使用针对性的代码对其处理
共性:a.都含有不正常情况的信息,引发原因等          b.都是通过抽取形成了超类Throwable
·RuntimeException:由程序错误导致的异常。
·IOException:程序本身没问题,由I/O错误导致的异常。
规则:若出现RuntimeException异常,一定是自己的问题。
2、Exception中异常划分:
1)编译时被检测异常(编译javac时会检查代码)该异常在编译时,若未处理(没有抛也没有try),编译失败,该异常被标识,代表可被处理。
2)运行时异常(编译时不检查)-RuntimeException:编译时,无需处理,编译器不检查该异常发生,建议不处理,让程序停止,需对代码进行修正。
RuntimeException:若在函数内抛出该异常,函数上可不用声明,也可通过,若在函数上声明了该异常,调用者可不用进行处理,编译也可通过。
可不在函数上声明,因为无需让调用者处理。当异常发生时,希望程序停止,因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
3、继承的异常简介:
1)继承于RuntimeException的异常情况:
·错误类型转换:ClassCastException
·空指针异常:NullPointerException
·数组访问越界:IndexOutOfBoundsException
2)非继承于RuntimeException的异常情况:
·试图在文件尾部读取数据
·试图打开一个错误格式的URL
·试图根据给定的字符串查找class对象,而此字符串表示的类不存在

三、异常的处理:
异常处理的任务:将控制权从错误产生的地方转移给能处理错误这种情况的错误处理器。
若函数上声明了异常,调用者需进行处理,处理方法可以throw,可以try。
1、对捕获的异常对象进行常见方法的操作:
trrows Exception:抛出异常
try-catch-finally:捕获异常 ---- java中提供了特有的语句进行处理。
String getMessage();获得异常信息
2、throw和throws的用法:
1)throw:定义在函数内,用于抛出异常对象。注:throw单独存在时,下面不要定义语句,因为执行不到,编译失败。
2)throws:定义在函数上,用于跑出异常类,可抛多个,用逗号隔开。
注:当函数内有throw抛出异常对象,必须给出对应的处理动作,若并未进行try处理,需在函数上声明,否则编译失败。
一般函数出现异常,需在函数上声明,但RuntimeException除外,若在函数内抛出此异常,函数上可不声明。
3、异常处理语句:
结合方式:
① try-chatch   ②try-finally  ③try-catch-finally
格式:
try
{
	//需要被检测的代码;
}
catch (异常类 变量)
{
	//理异常的代码;(处理方式)
}
finally
{
	//一定会执行的语句;
}

在函数上声明异常:便于提高安全性,让调用者进行处理,若不处理,则编译失败
注:finally中定义的通常为:关闭资源代码,因为资源必须被释放。
有一种情况不会执行finally,即出现System.exit(0);这条语句,后面的finally不会执行,因为这个代表系统退出吗,JVM结束。

    try
    {
	...
    }
    catch ()
    {
 	//......
	System.exit(0);
    }
    finally
    {
   	...
    }


4、多异常的处理:
1)声明异常时,建议声明更为具体的异常,这样处理更具体。
注:抛出几个具体的问题处理时,就具体处理哪些问题,而不是再加上catch(Exception e){...}让JVM自己将问题解决后再继续运行,那么调用者将不知道发生了什么问题。
2)原则:
对方声明几个异常,就对应几个catch块,不要定义多余catch,若多个catch块中的异常出现继承关系,父类异常catch块,放最下面(最大,处理更多)。
3)建议:
在进行catch处理时,catch中一定要定义具体处理方式,不要简单的定义一句:e.printStatckTrace();,也不要简单的打印一句。
遇到异常要怎么处理呢?常规做法是不打印异常信息,因为即时打印了,用户也无法解决掉,最好是将问题或信息记录下来,并存储为异常日志文件,便于程序员管理查阅,并及时修正代码,管理程序。
四、自定义异常:
1、概述:
因为项目中会出现特有问题,而这些问题并未被java所描述并封装成对象,所以这些特有问题可按java中对问题封装的思想,将特有问题进行定义的异常封装。
2、继承Exception或RuntimeException的原因:
1)异常体系有一个特点:异常类和异常对象都被抛出,他们都具有可抛性。这个可抛性是Throwable这个体系单独有的特点,只有此体系中的类和对象才可被throws和throw操作。
2)为了让该类具备操作异常的共性方法。
3、定义异常信息:

由于父类中把异常信息的操作完成了,所以子类只需要在构造函数时,将异常信息传递给父类,通过super语句,则可直接用getMessage方法,自动自定义的异常。

class MyException extends Exception
{
	MyException(String message)
	{
		super(message);
		....
	}
}

自定义异常时,若该异常的发生无法继续进行运算,就让自定义异常继承RuntimeException。
五、异常的好处:

1、将问题进行封装
2、将正常流程代码和问题处理代码相分离,便于阅读。
六、异常处理原则
1、处理方式:throw或throws
2、调用到抛出异常的功能时,抛几个,处理几个,一个try可以对应多个catch
3、多个catch,父类catch放在最下面。
4、catch内需要定义针对性的处理方式,不要定义printStackTrace,输出语句也不要不写,当捕获到异常,本功能处理不了时,可继续在catch中抛出
     若该异常处理不了,但不属于该功能出现的异常,可以讲异常转换后,再抛出或可处理异常,但需要将异常产生的和本功能相关的问题提供出去,让调用者知道并处理,也可以将捕获的异常处理后转换为新异常。如汇款的例子。示例:
try
{
	throw new AException();
}
catch (AException e)
{
	//方式一
	throw e;
	//方式二
	...处理AException语句
	throw new BException();
}

七、异常注意事项:
1、在子父类覆盖时:
1)子类抛出的异常须为父类异常的子类或子集
2)若父类或接口无异常抛出,子类覆盖的方法出现异常,只能try,不能抛。
2、异常机制:
1)只有在异常情况下使用异常,不可随处都用
2)不能过分的细化异常,即将正常程序和错误处理分开。这样也更清晰。
3)充分使用异常体系结构:Exception的体系很庞大,不要抛出由于逻辑错误造成的异常,要将一种异常转换成另一种更加适合的异常时,就需要抛出新异常,让可处理此异常的调用者处理。
4)不要压制异常:java中存在着强烈关闭异常的倾向。即使很难出现异常情况时,也要考虑异常的发生,并声明后将其关闭。
5)在检查错误时,要对异常“苛刻”一些,异常越是具体越好,将异常的范围缩小处理(或抛出)。
6)不要保留异常,要敢于传递异常:传递异常比捕获异常更好,让高层次的方法通告用户发生的错误,或者放弃不成功的命令更加合适。
原则:对于异常:早抛出,晚捕获。
参考例子:
/*
毕老师用电脑讲课
开始思考上课中出现的问题:如:电脑蓝屏、电脑冒烟
描述问题,封装成对象
可当冒烟发生后,出现讲课无法继续。
出现了讲师的问题:课程计划无法完成
*/
//自定义蓝屏异常
class LanPingException extends Exception
{
	LanPingException(String messgae)
	{
		super(messgae);
	}
}
//自定义冒烟异常
class MaoYanException extends Exception
{
	MaoYanException(String messgae)
	{
		super(messgae);
	}
}
//自定义课时无法继续异常
class NoPlanExceptioon extends Exception
{
	NoPlanExceptioon(String messgae)
	{
		super(messgae);
	}
}

class Computer
{
	//state为1时,正常;为2时,蓝屏;为3时,冒烟
	private int state = 3;

	public void run()throws LanPingException,MaoYanException
	{
		if (state ==2)
			throw new LanPingException("蓝屏了");
		if (state ==3)
			throw new MaoYanException("冒烟了");

		System.out.println("run");
	}
	//重启,恢复蓝屏异常
	public void reset()
	{
		state = 1;
		System.out.println("reset");
	}
}
//创建教师类
class Teacher
{
	private String name;
	Computer comp;//讲课要用电脑,初始化老师时就产生这个
	Teacher(String name)
	{
		this.name = name;
		comp = new Computer();
	}
	//定义上课方法
	public void prelect()throws NoPlanExceptioon//冒烟了就不要抛MaoYanException了,因为这个异常老师解决不了,直接抛出老师熟悉的异常
	{
		try
		{
			comp.run();
		}
		catch (LanPingException l)
		{
			comp.reset();
		}
		catch (MaoYanException m)//注意这里
		{
			test();
			throw new NoPlanExceptioon("课时无法继续" + m.getMessage());//再次抛出异常,抛给熟悉该异常的人
		}
		System.out.println("讲课");
	}
	public void test()
	{
		System.out.println("练习");
	}
}
//测试
class ExceptionTest
{
	public static void main(String[] args) 
	{
		Teacher t = new Teacher("毕老师");
		try
		{
			t.prelect();
		}
		catch (NoPlanExceptioon n)
		{
			System.out.println(n.toString());
			System.out.println("换老师或放假");
		}
		
	}
}

/*
有个圆形和长方形,都可以获取面积,对于面积若出现非法数值,是为获取面积出问题
问题通过异常来表示
*/
//创建输入值错误的异常
class NoValueException extends RuntimeException//对问题名称的描述,更具体
{
	NoValueException(String message)
	{
		super(message);
	}
}
//创建接口,抽取获取面积方法
interface ShapeArea
{
	void getArea();
}
//创建获取长方形面积的类
class Rec implements ShapeArea
{
	private int len,wid;
	//此处声明了,就会将问题抛给主函数中解决
	Rec(int len,int wid)throws NoValueException
	{
		if (len<=0 || wid<=0)
			throw new NoValueException("出现非法值了");
		this.len = len;
		this.wid = wid;
	}
	public void getArea()
	{
		System.out.println(len*wid);
	}

}
//创建获取圆形面积的类
class Circle implements ShapeArea
{
	private int rad;
	private static final double PI = 3.14;
	//此处未声明,当调用该函数,发生异常时会直接结束程序,并打印具体的异常信息
	Circle(int rad)
	{
		if (rad<=0)
			throw new NoValueException("出现非法值了");
		this.rad = rad;
	}
	public void getArea()
	{
		System.out.println(rad*rad*PI);
	}

}
//测试
class Exception
{
	public static void main(String[] args) 
	{
		//方式一:出现异常时,信息不具体
		try
		{
			Rec r= new Rec(-3,4);
			r.getArea();
		}
		catch (NoValueException e)
		{
			System.out.println(e.toString());
		}
		System.out.println("OVER");
		//方式二:出现异常时,信息更具体
		Circle c = new Circle(-8);
		c.getArea();
	}
}

一、实验步骤 1、创建maven web项目或者模块,导入相关软件的依赖包。 2、进行tomcat的相关配置。 3、在数据库mybatis中创建book表,并插入一条数据,sql语句如下: USE mybatis; CREATE TABLE `tb_book` ( `id` int(11) , `name` varchar(32) , `press` varchar(32) , `author` varchar(32) ); INSERT INTO `tb_book` VALUES (1, 'Java EE企业级应用开发教程', '人民邮电出版社', '黑马程序员'); 4、在src/main/java里创建com包,在里面创建itheima子包,在itheima包中分别创建controller,service,dao和domain包。 5、在domain包下创建名称为Book的实体类。代码如下: public class Book { private Integer id; //图书id private String name; //图书名称 private String press; //出版社 private String author; //作者 //getter和setter方法自行补充 @Override public String toString() { return super.toString(); } } 6、在dao包下创建接口BookMapper,里面创建一个根据id查询图书信息的方法,代码如下: public interface BookMapper { public Book findBookById(Integer id); } 7、在src/main/resources文件夹中,创建多级文件夹com/itheima/dao,在dao文件夹下,创建映射文件BookMapper.xml,记录与findBookById对应的sql语句。 <?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itheima.dao.BookMapper"> <!--根据id查询图书信息 --> <select id="findBookById" parameterType="int" resultType="com.itheima.domain.Book"> select * from tb_book where id = #{id} </select> </mapper> 8、在service包里创建BookService接口,在BookService接口中定义findBookById()方法,通过id获取对应的Book信息。代码如下: public interface BookService { public Book findBookById(Integer id); } 9、在service包中创建子包impl,在ipml包中创建BookServiceImpl类,BookServiceImpl类实现BookService接口的findBookById()方法,并在类中注入一个BookMapper对象。findBookById()方法通过注入的BookMapper对象调用findBookById()方法,根据id查询对应的图书信息。代码如下: public class BookServiceImpl implements BookService { @Autowired private BookMapper bookMapper; public Book findBookById(Integer id) { return bookMapper.findBookById(id); } } 10、在controller包中创建BookController类,在BookController类中注入一个BookService对象,并且定义一个名称为findBookById()的方法。findBookById()方法获取传递过来的图书id,并将图书id作为参数传递给BookService对象调用的findBookById()方法。代码如下: @Controller public class BookController { @Autowired private BookService bookService; @RequestMapping("/book") public ModelAndView findBookById(Integer id) { Book book = bookService.findBookById(id); ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("book"); modelAndView.addObject("book", book); return modelAndView; } } 11、在resources文件夹中创建jdbc.properties,作为数据库连接配置文件,代码如下: jdbc.driverClassName=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true\ &characterEncoding=utf-8&serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=root 12、在resources文件夹中创建Spring的配置文件application-dao.xml文件,用于扫描包,引入数据库连接配置文件,配置Spring和MyBatis的整合信息(包括SqlSessionFactoryBean类和MapperScannerConfigurer的配置)。代码如下: <!--开启注解扫描, 扫描包--> <context:component-scan base-package="com.itheima.service"/> <!--引入属性文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!--创建SqlSessionFactory对象--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--数据源--> <property name="dataSource" ref="dataSource"/> </bean> <!--扫描Dao包,创建动态代理对象,会自动存储到spring IOC容器中--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--指定要扫描的dao的包--> <property name="basePackage" value="com.itheima.dao"/> </bean> 13、在src/test/java目录下,创建名称为BookTest的测试类,用于对Spring和MyBatis的整合进行测试。用上@RunWith和@ContextConfiguration注解,代码如下,对此方法进行测试,成功打印出书籍信息即可证明Spring和MyBatis整合成功。 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations ="classpath:application-dao.xml") public class BookTest { @Autowired private BookService bookService; @Test public void findBookById() { Book book = bookService.findBookById(1); System.out.println("图书id:" + book.getId()); System.out.println("图书名称:" + book.getName()); System.out.println("作者:" + book.getAuthor()); System.out.println("出版社:" + book.getPress()); } } 14、下面对Spring和SpringMVC进行整合。在resources目录下创建Spring MVC的配置文件spring-mvc.xml,负责扫描controller层以及配置视图解析器。代码如下: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置要扫描的包 --> <context:component-scan base-package="com.itheima.controller"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="suffix" value=".jsp"/> </bean> <!-- 配置默认Servlet,处理静态资源 --> <mvc:default-servlet-handler/> <!-- 配置注解驱动 --> <mvc:annotation-driven/> </beans> 15、在项目的web.xml中配置Spring的监听器ContextLoaderListener来加载Spring容器及Spring的配置文件,具体配置如下所示: <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application-*.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 16、接着在web.xml中配置SpringMVC的前端控制器,并在初始化前端控制器时加载Spring MVC的的配置文件spring-mvc.xml。代码如下: <!--Spring MVC 前端控制器--> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <!--初始化参数--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <!--项目启动时候,初始化前端控制器--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> 17、在webapp目录下创建book.jsp,代码如下: <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html> <head><title>图书信息查询</title></head> <body> <table border="1"> <tr> <th>图书id</th> <th>图书名称</th> <th>出版社</th> <th>作者</th> </tr> <tr> <td>${book.id}</td> <td>${book.name}</td> <td>${book.press}</td> <td>${book.author}</td> </tr> </table> </body> </html> 18、运行项目,在浏览器地址栏中输入http://localhost/book?id=1来进行图书查询。如果能顺利访问,表示SSM整合成功(如果你端口是80的话,访问url得加上端口)。 用idea按照以上流程,详细的列出每一步的步骤,教会小白。
最新发布
06-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值