1、引入异常并进行简单处理
问题1:异常是什么?
异常:程序在运行过程中出现了可逆转或不可逆转的错误现象,异常处理已经成为衡量一门语言是否成熟的标准之一,目前的主流编程语言如:C、C++、C#、Ruby、python、Java等都提供了异常处理机制。
异常处理的目的:为了提高系统的健壮性、稳定性,良好的系统的设计应该有完整的异常处理。因为如果不处理异常,异常会直接交给JVM,jvm会报错,并将结束程序。
1.1、示例引出异常
/**
-
功能:输入被除数和除数,求商并输出
-
技能:引入异常
-
Java提供了异常处理机制,一旦出现异常,Java会捕获并继续处理
-
问题1:一旦出现异常,后续的语句不执行
-
问题2:Java系统提供的异常提示信息过于专业,不友好
-
解决:
-
方案1:通过if-else进行判断,如果输入的是非数字,如果输出是0,给出提示信息
-
- 不可行!!
1、代码臃肿
2、程序员要花很大精力"堵漏洞“
3、程序员很难堵住所有“漏洞”
- 不可行!!
-
方案2:在Java提供的异常处理机制的基础上,进行简单的捕获和处理即可
-
try--catch-finally
-
throws throw
*/
/**
- 尝试通过if-else来解决异常问题。
- 不可行!!
1、代码臃肿
2、程序员要花很大精力"堵漏洞“
3、程序员很难堵住所有“漏洞”
*/
public class Test2 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("请输入被除数:");
int num1 = 0;
if (in.hasNextInt()) { // 如果输入的被除数是整数
num1 = in.nextInt();
} else { // 如果输入的被除数不是整数
System.err.println("输入的被除数不是整数,程序退出。");
System.exit(1); // 结束程序执行
}
System.out.print("请输入除数:");
int num2 = 0;
if (in.hasNextInt()) { // 如果输入的除数是整数
num2 = in.nextInt();
if (0 == num2) { // 如果输入的除数是0
System.err.println("输入的除数是0,程序退出。");
System.exit(1);
}
} else { // 如果输入的除数不是整数
System.err.println("输入的除数不是整数,程序退出。");
System.exit(1);
}
System.out.println(String.format("%d / %d = %d",
num1, num2, num1/ num2));
System.out.println("感谢使用本程序!");
System.out.println("程序运行结束");
}
}
1.2、使用try-catch进行异常处理
问题2:如何解决异常
使用:try-catch
/**
功能:输入被除数和除数,求商并输出
技能:使用try-catch进行异常处理
总结:
1.什么是异常(Exception)
异常( Exception 也称例外)就是在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序
2.try-catch进行异常处理的执行过程
情况1:try块中代码没有出现异常
不执行catch块代码,执行catch块后边的代码
情况2:try块中代码出现异常,catch中异常类型匹配(相同或者父类)
try块中后续语句不执行-----执行catch块代码-----执行catch块后边的代码
情况3:try块中代码出现异常, catch中异常类型不匹配
try块中后续语句不执行-----不执行catch块代码------------不执行catch块后边的代码,程序会中断运行
3.catch块中如何处理异常
输出用户自定义异常信息
System.err.println("除数不能为零。");
System.err.println("被除数和除数必须是整数。");
调用异常对象的方法输出异常信息
toString ( )方法,显示异常的类名和产生异常的原因
void printStackTrace() 输出异常的堆栈信息
String getMessage()返回异常信息描述字符串,是printStackTrace()输出信息的一部分
继续向上抛出异常
throw e
4.强调
- 1.出现异常后,Java会生成相应的异常对象,Java系统,寻找匹配的catch块,找到后将异常对象付给catch块异常参数
- 2.出现异常后,try块中尚未执行的语句不会执行
- 3.出现异常后并处理后,catch块后面的语句还会执行
*/
public class Test3 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
try{
//输入被除数
System.out.println("请输入被除数");
int num1 = input.nextInt();//InputMismatchException
//输入除数
System.out.println("请输入除数");
int num2 = input.nextInt();
//求商输出结果
System.out.println(num1+"/"+num2+"="+num1/num2);
}catch(Exception e){
//1.用户自定义信息
//System.out.println("被除数和除数必须是数字,除数不能是0");
//2.使用java提供的异常信息
//System.out.println(e.toString());
//System.out.println(e.getMessage());
//e.printStackTrace();
//3.继续向上抛出异常(catch后续代码不执行)
throw e;
}
//谢谢使用
System.out.println("谢谢你的使用");
System.out.println("程序结束");
}
}
2、使用try-catch-finally处理异常
功能:输入被除数和除数,求商并输出
技能:使用try-catch-finally进行异常处理
问题1:在什么情况,System.out.println(“谢谢你的使用”);System.out.println(“程序结束”);不执行
- 情况1:catch块中有throw语句
- 情况2:没有匹配的catch块语句 InputMismatchException / ArithmeticException
- 情况3:遇到return语句
问题2:即使出现如上三种情况,希望某些语句也必须执行
解决:finally语句
问题3:哪些语句可以放到finally语句中
- 关闭数据库连接 conn.close();
- 关闭IO流 fis.close()
- 关闭socket连接 socket.close()
问题4:是不是所有情况下finally语句都执行
- 唯一例外
- System.exit(0):退出JVM 程序结束
- 0:正常终止 / 非 0 的状态码表示异常终止
- return:结束当前方法
示例:
public class Test4 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
try{
//输入被除数
System.out.println("请输入被除数");
int num1 = input.nextInt();//InputMismatchException
//输入除数
System.out.println("请输入除数");
int num2 = input.nextInt();
//求商输出结果
System.out.println(num1+"/"+num2+"="+num1/num2);
System.exit(0);
//return;
}catch(Exception e){
//1.用户自定义信息
System.err.println("被除数和除数必须是数字,除数不能是0");
//2.使用java提供的异常信息
System.err.println(e.toString());
//System.out.println(e.getMessage());
//e.printStackTrace();
//3.继续向上抛出异常(catch后续代码不执行)
//throw e;
return;
}finally{
//谢谢使用
System.out.println("谢谢你的使用");
}
System.out.println("程序结束");
}
}
3、多重catch和异常分类
3.1、多重catch
问题:System.err.println(“被除数和除数必须是数字,除数不能是0”);
* 不完全准确,到底是哪种错误
解决:多重catch
ArithmeticException
InputMismatchException
技能:使用多重catch进行精确的异常处理
注意:
1.依次和各个catch块进行比较,如果匹配,执行该catch块的代码,后续catch块不会比较和执行
2.各个catch块的顺序:先子类后父类
3.多个catch最多执行一个.
Error
Exception
-RuntimeException
-Checked Exception
示例
/**
- 功能:输入被除数和除数,求商并输出
- 技能:使用多重catch进行异常处理
问题:System.err.println(“被除数和除数必须是数字,除数不能是0”);
*不完全准确,到底是哪种错误
*解决:多重catch *
注意: - 1.依次和各个catch块进行比较,如果匹配,执行该catch块的代码,后续catch块不会比较和执行
- 2.各个catch块的顺序:先子类后父类
- 3.多个catch最多执行一个
*/
public class Test5 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
try{
//输入被除数
System.out.println("请输入被除数");
int num1 = input.nextInt();//InputMismatchException
//输入除数
System.out.println("请输入除数");
int num2 = input.nextInt();
//求商输出结果
System.out.println(num1+"/"+num2+"="+num1/num2);
System.exit(0);
//return;
}catch(ArithmeticException e){
System.err.println("除数不能是0");
}catch(InputMismatchException e){
System.err.println("被除数和除数必须是数字");
}catch(Exception e){
System.err.println("其他异常");
e.printStackTrace();
}finally{
//谢谢使用
System.out.println("谢谢你的使用");
}
System.out.println("程序结束");
}
}
3.2、异常分类
示例
/**
- 异常的分类
- 1.运行时异常(RuntimeException)
- 用户可以处理也可以不处理
- 2.检查异常(Checked Exception)编译时异常
- 用户必须进行异常处理,否则编译出错
- 怎么处理
- 1.try-catch-finally
- 2.throws
*/
public class Test6 {
public static void main(String[] args) throws IOException {
//1
// String str = null;
// System.out.println(str.toLowerCase());
//2
Scanner input = new Scanner(System.in);
//输入被除数
System.out.println("请输入被除数");
int num1 = input.nextInt();
//3
try {
Class.forName("com.bjsxt.exception.test.Test1").newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
//4
InputStream is = new FileInputStream("c:/abc.txt");
is.close();
}
}
异常分类总结
Throwable 类
– Error
–Exception
- 运行时异常 Runtime Exception(unchecked Exception)
-
RuntimeException
-
-- ArithmeticException
-
-- InputMismatchException
-
-- NullPointerException
-
-- ArrayIndexOutOfBoundsException
-
可以不要处理
2.检查异常(Checked Exception) 编译时异常
检查时异常 Checked Exception 编译时的异常
–SQLException
–ClassNotFoundException
–FileNotFoundException
–IOException
我们必须处理
例如:
Class.forName(“com.sxt.exception.Test”);
Class.forName(“com.sxt.exception.Test”).newInstance();
InputStream is = new FileInputStream(“e:/abc.txt”);
is.close();
用户必须进行异常处理,否则编译出错
怎么处理?
1.try-catch-finally
2.throw/throws
总结:
Java编译器要求Java程序必须捕捉处理或声明抛出所有的 检查时异常(Exception)。
但对 运行时异常(RuntimeException) 可以不作处理。
注意:只有Java提供了Checked检查时异常,体现了Java的严谨性,提高了Java的健壮性。同时也是一个备受争议的问题。
4、throw 异常_除数不能是负数
throw 和 throws
/**
- 功能:给出被除数和除数,求商并输出;如果除数是负数,也抛出异常
- 技能:throws throw
*/
public class Test7 {
public static void main(String[] args) throws Exception {
// try {
// devide();
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
devide();
}
public static void devide() throws Exception{
Scanner input = new Scanner(System.in);
//输入被除数
System.out.println("请输入被除数");
int num1 = input.nextInt();
//输入除数
System.out.println("请输入除数");
int num2 = input.nextInt();
//如果除数是负数,也抛出异常
if(num2<0){
//throw new RuntimeException("除数不能是负数"); 运行异常
throw new Exception("除数不能是负数"); 检查异常 必须处理
}
//求商输出结果
System.out.println(num1+"/"+num2+"="+num1/num2);
//谢谢使用
System.out.println("谢谢你的使用");
System.out.println("程序结束");
}
}
总结:
throw和throws的区别 |
---|
1.位置不同 throw位于方法体中,throws位于方法声明中 |
2.内容不同 throw 后面跟一个异常对象,throws后面跟一个或多个异常类 |
3.作用不同 throw 此处有异常,我负责抛出,这里是异常的源头; |
throws:该方法中有异常,但是没有进行try-catch,我负责声明,告诉调用者 |
5、throw异常案例
throws throw 案例之性别只能是男女
功能:Person类的性别只能是男或者女,否则抛出异常
Person类的年龄只能在1—130直接,否则抛出异常
//throw new RuntimeException(“性别只能取值男或者女”);
throw new Exception(“性别只能取值男或者女”); //检查异常
检查异常的处理:要么抛出,要么处理
public class Person {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) throws Exception{
if("男".equals(sex)|| "女".equals(sex)){
this.sex = sex;
}else{
//this.sex = "男";
//throw new RuntimeException("性别只能取值男或者女");
throw new Exception("性别只能取值男或者女");
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
/**
- 功能:Person类的性别只能是男或者女,否则抛出异常
-
Person类的年龄只能在1---130直接,否则抛出异常
*/
public class Test8 {
public static void main(String[] args) {
Person p = new Person();
p.setName("xiaohong");
try {
p.setSex("123");
p.setAge(200);
System.out.println(p);
} catch (Exception e) {
e.printStackTrace();
}
//Class.forName("");
}
}
6、自定义异常
为了让异常信息更 直观、人性化,可以采用 自定义异常
(1) SexException extends RuntimeException 性别异常
(2) DevideByMinusException extends Exception 为负数异常
自定义异常
- 1.继承Exception或者RuntimeException
- 2.重写父类的两个构造方法:无参数构造方法和输入message的有参数构造方法
- 3.自定义异常可以有额外的成员变量,具体值可以通过构造方法传入,此时一般要重写toString()
示例1:继承RuntimeException
/**
- 自定义异常
- 1.继承Exception或者RuntimeException
- 2.重写父类的两个构造方法:无参数构造方法和输入message的构造方法
- 3.自定义异常可以有额外的成员变量,具体值可以通过构造方法传入,此时一般要重写toString()
*/
public class SexException extends RuntimeException{
public SexException() {
super();
}
public SexException(String message) {
super(message);
}
}
public class Person {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
if("男".equals(sex)|| "女".equals(sex)){
this.sex = sex;
}else{
//this.sex = "男";
//throw new RuntimeException("性别只能取值男或者女");
throw new SexException("性别只能取值男或者女");
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
/**
- 功能:Person类的性别只能是男或者女,否则抛出异常
-
Person类的年龄只能在1---130直接,否则抛出异常
*/
public class Test8 {
public static void main(String[] args) {
Person p = new Person();
p.setName("xiaohong");
try {
p.setSex("123");
p.setAge(200);
System.out.println(p);
} catch (SexException e) {
e.printStackTrace();
}
//Class.forName("");
}
}
注意:由于SexException是运行时异常,所以try{}catch{}可以不写。
示例2:继承Exception
public class DevideByMinusException extends Exception{
private int minus;
public DevideByMinusException() {
super();
}
public DevideByMinusException(String message) {
super(message);
}
public DevideByMinusException(String message, int minus) {
super(message);
this.minus = minus;
}
@Override
public String toString() {
return super.toString()+"("+minus+")";
}
}
/**
- 功能:给出被除数和除数,求商并输出;如果除数是负数,也抛出异常
*/
public class Test7 {
public static void main(String[] args){
// try {
// devide();
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
try {
devide();
} catch (DevideByMinusException e) {
System.out.println(e.toString());
//e.printStackTrace();
}
}
public static void devide() throws DevideByMinusException {
Scanner input = new Scanner(System.in);
//输入被除数
System.out.println("请输入被除数");
int num1 = input.nextInt();
//输入除数
System.out.println("请输入除数");
int num2 = input.nextInt();
//如果除数是负数,也抛出异常
if(num2<0){
//throw new RuntimeException("除数不能是负数");
throw new DevideByMinusException("除数不能是负数",num2);
}
//求商输出结果
System.out.println(num1+"/"+num2+"="+num1/num2);
//谢谢使用
System.out.println("谢谢你的使用");
System.out.println("程序结束");
}
}
4、异常链及案例
- //对底层异常进行处理(给程序员)
System.out.println(“程序员看到的异常信息:”+e);
//抛出一个更友好的异常(给用户)
throw new AuctionException(“竞拍价格必须是数字”);
标准javaBean – java实体类
标准java Bean的基本条件:
(1)必须提供私有的成员变量。
(2)必须为私有的成员变量提供公有的set/get方法。
(3)必须有无参的构造方法。
示例
/**
*功能:用户输入拍卖价格,系统将拍卖价格保存到数据库中,给出提示信息
*技能:异常转译/异常链 分层结构
*Auction拍卖 bid 竞价
*1.分层结构
*用户
*表示层(视图层)
*业务层Service
*数据访问层DAO
*数据库
- 下一层为上一层提供服务,上一层直接调用下层提供的服务即可
-
- 2.异常转译
- //对底层异常进行处理(给程序员)
System.out.println(“程序员看到的异常信息:”+e);
//抛出一个更友好的异常(给用户)
throw new AuctionException(“竞拍价格必须是数字”);
*/
public class Client {
public static void main(String[] args) {
//输入价格
//String sprice ="123";
String sprice ="123abc";
//完成业务
AuctionService as = new AuctionService();
try {
as.bid(sprice);
} catch (AuctionException e) {
//System.out.println("客户看到的异常信息:"+e.getMessage());
System.out.println("客户看到的异常信息:"+e);
}
}
}
/**
- 数据访问层,访问数据库
*/
public class AuctionDao {
//保存竞价到数据库中
public void savePrice(String sprice){
//转换成数字
int price = Integer.parseInt(sprice);//"123"---123 "abc"---???
//保存到数据库中
System.out.println("将价格保存到数据库中:"+price);
}
}
/**
- 业务层
*/
public class AuctionService {
//完成竞价业务
public void bid(String sprice) throws AuctionException{
AuctionDao ad = new AuctionDao();
try{
ad.savePrice(sprice);
}catch(NumberFormatException e){
//对底层异常进行处理(给程序员)
System.out.println("程序员看到的异常信息:"+e);
//抛出一个更友好的业务异常(给用户)
throw new AuctionException("竞拍价格必须是数字");
}
}
}
/**
- 拍卖异常
*/
public class AuctionException extends Exception{
public AuctionException() {
super();
}
public AuctionException(String message) {
super(message);
}
}
总结
1、运行时异常和Checked异常有什么区别?
简单来说运行时异常可以不处理,编译时异常必须要处理
2、多重catch块的执行顺序?
子类先执行
3、throw和throws关键字有什么区别?
throws出现在方法函数头;而throw出现在函数体。
throws表示出现异常的一种可能性,并不一定会发生这些异常;
throw则是抛出了异常,执行throw则一定抛出了某种异常对象。