10.17-设计模式与异常
设计模式(Design Pattern)
是一套被反复使用、多数人知晓的、经过分类的代码设计经验的总结
使用设计模式的目的很简单:为了代码的可重复性,让代码更容易被他人理解,保证了代码的可靠性。
设计模式使代码的编程真正的工程化,设计模式是软件工厂的基石脉络,如同大厦的结构一般。
分类
设计模式可以分为三大类
创建型模式:单例模式、工厂模式等等
结构型模式:装饰模式、代理模式等等
行为型模式:模板模式、迭代器模式等等
单例模式(Singleton Pattern)
单例模式是Java中最简单的设计模式(思想)之一,这种设计模式属于创建型模式;它提供了一种创建对象的最佳方式,即保证一个类只有一个实例,并提供了一个访问它的全局访问点
例子
package se02;
//单例模式示例(饿汉式)
public class Singleton {
//第一步:私有化构造器
private Singleton(){
}
//第二步:声明一个私有的、静态的当前类的实例
private static Singleton instance = new Singleton();
//第三步:声明一个公有的、静态的、能够返回当前实例的方法
public static Singleton getInstance() {
return instance;
}
public void showMessage() {
System.out.println("Hello Singleton");
}
}
测试类
package se02;
public class SingletonDemo {
public static void main(String[] args) {
// Singleton t1 =new Singleton();
// t1.showMessage();
// Singleton t2 =new Singleton();
// t2.showMessage();
// System.out.println(t1==t2);//false
Singleton t1 = Singleton.getInstance();
t1.showMessage();
Singleton t2 = Singleton.getInstance();
t2.showMessage();
System.out.println(t1==t2);//true,其引用的为同一个对象instance
}
}
模板模式
所谓的模板模式指的是定义一个操作中算法过程骨架,而将一些步骤延迟到子类中去实现
示例
首先创建模板类
package se02;
//模板模式示例
public abstract class Template {
//定义一个自我介绍的模板
public void sayHello() {
System.out.println("大家好");
sayName();
sayInfo();
System.out.println("谢谢!");
}
//介绍姓名的方法
public abstract void sayName();
//介绍个人信息
public abstract void sayInfo();
}
再创建实现类
package se02;
//模板实现类
public class CXK extends Template{
@Override
public void sayName() {
System.out.println("我叫菜虚困!");
}
@Override
public void sayInfo() {
System.out.println("我是一名练习时长两年半的个人练习生");
System.out.println("我喜欢唱、跳、Rap、篮球");
}
}
package se02;
public class CNW extends Template{
@Override
public void sayInfo() {
System.out.println("我是x");
System.out.println("我琴日");
}
@Override
public void sayName() {
System.out.println("我叫小蔡!");
}
}
最终创建测试类
package se02;
public class TemplateDemo {
public static void main(String[] args) {
Template cxk = new CXK();
Template cyw = new CNW();
cxk.sayHello();
cyw.sayHello();
}
}
Java中异常结构的父类Throwable(问题类)
其派生出了两个子类别
Error:表示JRE的错误,该类问题无法通过修改程序来解决
StackOverflowError:栈内存溢出
OutOfMemoryError:堆内存溢出
Exception:表示程序级别的异常,该类问题可以通过修改程序来解决
注意
异常是行为、方法、过程的意外结果
一个方法如果抛出(throw)了异常,那么这个方法就必须声明异常的抛出(throws)
异常的声明:在方法上声明方法的意外结果
异常类一般都继承自Exception
如果调用一个抛出异常的方法,则必须要处理异常;有两种方案:
使用try-catch-finally捕获异常,并解决异常
使用throws关键字直接抛出异常
如果出现异常,异常以后的代码将不再执行(除了finally类当中的代码)
Java异常捕获机制(try-catch)
语法
try{//try块
//有可能出现异常的代码片段
}catch(XXXException e){//catch块
//解决异常的代码片段(catch块跟在try块之后,用于捕获并解决异常,catch块可以出现多次)
}finally{//finally块(可以省略不写)
//不论是否出现异常,finally块内代码永远会被执行
//通常我们使用finally语句作为程序的收尾工作
}
例子
package se02;
public class ExceptionDemo01 {
/**
* Java异常捕获机制
* 程序中只能解决Exception,不能解决Error
*/
public static void main(String[] args) {
System.out.println("程序开始了");
// String str = null; //空指针
// String str = ""; //下标越界
String str = "13a2";
/*
* 当JVM发现我们使用null去调用方法,
* JVM会创建一个空指针异常实例来描述这里发生的异常情况,
* 并在当前行将异常实例抛出;
* 异常抛出后,JVM会检查代码片段中是否有异常处理机制,
* 当发现代码中没有异常处理机制后,则将该异常抛出到当前代码所在的方法之外,
* 当异常逐级抛到main方法之外,那么JVM会kill掉当前程序,程序将直接退出。
* 也就是说,异常代码下面的代码不会被执行
*/
//System.out.println(str.length());//空指针异常
try {
// System.out.println(str.length());
// System.out.println("内容都执行了");
// System.out.println(str.charAt(0));//下标越界
/*
* 当上面的代码出现了异常,会直接跳出这个try块
* 那么在try块中剩余的代码将不再执行
*/
int i = Integer.parseInt(str);
}catch(NullPointerException e) {
System.out.println("出现了空指针异常");
}catch(StringIndexOutOfBoundsException e) {
System.out.println("出现了下标越界异常");
}catch(Exception e ) {
/*
* 异常捕获机制的良好习惯
* 在最后一个catch中捕获Exception
* 以保证程序会捕获其他未知异常
* 使程序不会出现"闪退"的情况
*/
System.out.println("出现未知异常");
}
System.out.println("程序结束了");
}
}
throw关键字(主动抛出异常)
通常在以下两种情况会主动抛出异常:
当前语法片段出现了一个不满足业务逻辑情况的异常,我们需要主动抛出异常
当前代码片段出现的异常,但是该异常的处理不应该是当前代码片段负责时,我们需要主动的抛出异常
例子-主动异常抛出并处理异常
package se02;
public class ExceptionDemo03 {
/**
* 该类用于演示不满足业务逻辑时的异常抛出
*/
public static void main(String[] args) {
Person p = new Person();
try {
p.setAge(-23);
}catch(Exception e) {
//打印异常出现的原因
// System.out.println(e.getMessage());
//输出异常出现的堆栈信息
e.printStackTrace();
}
System.out.println(p);
}
}
class Person{//人类
private int age;
public void setAge(int age){
if(age<0||age>200) {
/*
* 如果出现一个与业务逻辑不符的异常,
* 我们可以使用throw这个关键字主动的抛出一个异常实例
* 该构造器支持传入一个String类型的参数,
* 该参数用于指定造成异常的原因
*/
throw new RuntimeException("不是人的年龄");
}
this.age=age;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "年龄"+age;
}
}
例子-主动异常抛出但不处理异常
package se02;
public class ExceptionDemo04 {
/**
* 该类用于演示不满足业务逻辑时的异常抛第二种情况
*/
public static void main(String[] args) {
connectDB("admin", "root");
System.out.println("数据库登陆成功");
}
//定义方法,模拟用户登录数据
public static void connectDB(String user,String pwd) {
if("admin".equals(user)&&"root1234".equals(pwd)) {
System.out.println("数据库链接成功");
}else {
//模拟数据库系统抛出一个数据库链接失败的异常
throw new RuntimeException("数据库链接失败");
}
}
}
throws关键字
该关键字用于在声明方法时连同声明该方法可能抛出的异常种类
以通知调用者在调用这些方法时应当对方法中的这些异常进行处理
Java中将异常分为检查异常和非检查异常
非检查异常:RuntimeExcetion及其子类
当程序中抛出(throw)了一个RuntimeExcetion及其子类时,Java编译器会在编译时不检查该类是否被处理
检查异常:除了RuntimeExcetion及其子类
当程序中抛出(throw)了一个检查异常时,Java编译器会在编译时检察该类异常是否有处理代码,如果没有则编译不通过
例子
package se02;
public class ExceptionDemo05 {
public static void main(String[] args){
try {
System.out.println(test(4,0,3));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("程序结束了");
}
/*
* 定义方法,先使用a/b,之后再将商加上c返回
* 当我们调用的方法会出现异常时,而我们的方法也不关心这个异常时,
* 我们可以采取在当前方法上继承声明throws,将该异常抛给方法的调用者
*/
public static int test(int a,int b,int c) throws Exception {
return divide(a, b)+c;
}
/*
* 定义一个除法操作(求两个整数相除的商)
* 当一个方法中使用throw主动抛出异常时,
* 该方法就应该书写throws来声明该异常的抛出
*/
public static int divide(int a,int b) throws Exception {
if(b==0) {
throw new Exception("除数不能为0");
}
return a/b;
}
}
练习
1.编写一个程序,以说明catch(Exception e)如何捕获 各种异常。
2.创建一个Exception类的子类DivideByZeroException, 代表除数为0异常;编写一个TestDivideByZero类, 该类包括一个方法div(double a,double b),实现两 个参数的相除操作,如果b为0,则生成异常对象, 并抛出异常,否则得到a/b的结果。 然后在main函数中调用div方法,然后处理异常。
最后更新于