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:表示程序级别的异常,该类问题可以通过修改程序来解决

注意

  1. 异常是行为、方法、过程的意外结果

  2. 一个方法如果抛出(throw)了异常,那么这个方法就必须声明异常的抛出(throws)

  3. 异常的声明:在方法上声明方法的意外结果

  4. 异常类一般都继承自Exception

  5. 如果调用一个抛出异常的方法,则必须要处理异常;有两种方案:

    1. 使用try-catch-finally捕获异常,并解决异常

    2. 使用throws关键字直接抛出异常

  6. 如果出现异常,异常以后的代码将不再执行(除了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方法,然后处理异常。

最后更新于