Java设计模式,内部类和异常

这周学习了设计模式,内部类,异常的相关概念知识.

一.设计模式概念

1.定义

​ Java 包含23种设计模式,是一套对代码设计经验的总结,被人们反复利用,多人熟知的代码设计方式.

2.目的

为了提高代码的可读性,可扩展性以及复用性,为了解决在写代码过程中遇到的代码设计问题.

3.设计模式的六大原则

实体功能独立,多实现接口,增强扩展性

1.开闭原则:

扩展开放,对修改关闭.尽可能对代码少修改.

2.里式替换原则:

任何父类(基类)出现的地方,子类都可以出现,也就是子类可以替换父类的任何功能(体现了父类的可扩展性)

3.依赖倒转原则:

尽可能面向接口编程,依赖接口而不依赖类,依赖于抽象而不依赖于具体

4.接口隔离原则

一个类如果能实现多个接口,尽可能实现多个,从而降低依赖,降低耦合.

5.最少知道原则

一个实体尽可能少的与其他实体产生相互关联关系,将实体的功能独立

6.合成复用原则

尽量使用合成,聚合的方式,而不使用继承(类似依赖倒转原则)

4.设计模式的分类

总体来说设计模式分为三大类:

1.创建型模式(5个)

单例模式,工厂方法模式,抽象工厂模式,建造者模式

2.结构型模式(7个)

适配器模式,装饰模式,代理模式,外观模式,桥接模式,组合模式,享元模式

3.行为型模式(11个)

策略模式,模板方法模式,观察者模式,迭代子模式,责任链模式,命令模式,状态模式,访问者模式,中介模式,解释器模式,备忘录模式

其实还有两类:并发型模式和线程池模式

/**设计模式参考:
file:///Users/yanjiamin/Desktop/Java/ppt和代码/Java设计模式/Java开发中的23种设计模式详解(转)%20-%20maowang%20-%20博客园.htm
**/

5.常用设计模式

1.单例模式

​ 是创建对象的一种特殊方式,创建一个 类对象后,程序从始至终使用的都是同一个 类对象叫单例(单实例).

​ 在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在

单例模式有3个好处:

1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销.

2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力.

3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了.(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程.

按创建对象方式不同可分为两类:

1.懒汉式单例:在使用时创建一个对象

2.饿汉式单例:在类加载时创建一个对象

1.懒汉式单例

1.定义一个空的静态类引用变量(属性)

2.将构造器私有化

3.创建该类的对象并提供一个静态的方法返回

/**
 * @Description:懒汉式单例
 * @author yanjiamin
 * @date 2020年10月13日 上午10:17:25
 */

public class Person {
  //1.私有静态属性实例 防止其他类直接引用该成员  此处赋值为null,目的是实现延迟加载
    private static Person person=null;


    //2.将构造器私有化  防止被实例化
    private Person (){


    }
    //3.提供一个静态的方法,并可返回该类的对象    静态工程方法,创建实例
    public static Person getInstance(){
        if(person==null){ 
          // 第一次访问
            person = new Person();
        }
        return person;
    }
    public void play() {
		System.out.println("Person===玩.....");
	}
}
2.饿汉式单例

1.创建一个类的静态对象

2.将构造器私有化

3.提供一个静态的方法返回该类的对象

public class Student {
    //1.在类加载时创建一个对象
    private static Student student = new Student();

    // 2.构造器私有化
    private Student(){

    }
    // 3.提供返回类对象的静态方法
    public static Student getInstance(){
        if(student !=null){
            return student;
        }
         return null;
    }
}

测试:

public class Test {
public static void main(String[] args) {
	//多例模式   每一次创建得到的是不同的对象
	Animal an1=new Animal();
	Animal an2=new Animal();
	an1.play();
	System.out.println(an1);
	an2.play();
	System.out.println(an2);
	
	//单例模式
	//懒汉式单例
	Person p1=Person.getInstance();
	Person p2=Person.getInstance();
	p1.play();
	System.out.println(p1);
	p2.play();
	System.out.println(p2);
	//Person p3=new Person();构造器私有化了,不能随意创建Person对象
	
	//饿汉式单例
	Student s1=Student.getStudent();
	Student s2=Student.getStudent();
	s1.play();
	System.out.println(s1);
	s2.play();
	System.out.println(s2);
}
}

2.工厂方法模式

​ 创建对象的过程不再由当前类实例化,而是由工厂类完成,在工厂类中只需要告知对象类型即可.工厂模式中必须依赖接口.(比如生产电脑,自己生产相当复杂,转而交给专业的工厂代为生产)

1.普通工厂模式

​ 就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建

以生产“电脑”为例,电脑有办公的功能,可以生产一体机或者笔记本

* @Description:
 * 生产电脑的工厂
 *先创建工厂再生产电脑
 * @author yanjiamin
 * @date 20201013日 上午11:17:37
 */
public class ComputerFactory1{
public Computer produce(String type) {
	Computer computer=null;
	if (type.equals("personalComputer")) {
		computer=new PersonalComputer();
		
	}else if (type.equals("workComputer")) {
		computer=new WorkComputer();
	}else {
		System.out.println("不能生产");
	}
	return computer;
}
}
2.多个工厂方法模式

是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象

以生产汽车为例,不同品牌的汽车有不同的生产工厂

public interface Car {
    public void  showInfo();
}

public class AudiCar implements Car {
    @Override
    public void showInfo() {
        System.out.println("这是一台奥迪汽车。。");
    }
}
public class BMWCar implements Car {
    @Override
    public void showInfo() {
        System.out.println("这是一台宝马汽车。");
    }
}
/**
生产汽车的工厂接口
**/
public interface CarFactory {
    public Car produce();
}
public class AudiCarFactory implements  CarFactory {
    @Override
    public Car produce() {

        return  new AudiCar();// 这里AudiCar是Car的实现类
    }
}
public class BMWCarFactory implements CarFactory {
    @Override
    public Car produce() {
        return new BMWCar();// 因为BWMCar是Car的实现类
    }
}

 public class Test1 {
        public static void main(String[] args) {
            //先创建 汽车工厂
            CarFactory bmwFactory = new BMWCarFactory();
            // 这个工厂生产的汽车就是 宝马
            Car bmw = bmwFactory.produce();
            bmw.showInfo();
    
            //这个模式对于同一级别的产品,可扩展性高
            //可以扩展不同品牌的汽车,此时不需要修改代码,只需要增加代码即可
            // 创建一个新的品牌汽车  大众汽车
    
            CarFactory dazhongFactory = new DazhongCarFactory();
            Car car = dazhongFactory.produce();
            car.showInfo();
        }
    }
3.静态工厂模式

将工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可

/**
 * @Description:静态工厂方法模式
 * 不用创建工厂,直接生产,节约资源,缺点是一旦创建一直存在
 *找已经建好的工厂生产电脑
 * @author yanjiamin
 * @date 2020年10月13日 上午11:34:15
 */
public class ComputerFactory2 {
	public static Computer produce(String type) {
		Computer computer=null;
		if (type.equals("personalComputer")) {
			computer=new PersonalComputer();
			
		}else if (type.equals("workComputer")) {
			computer=new WorkComputer();
		}else {
			System.out.println("不能生产");
		}
		return computer;
	}
}

测试:

public class Test {
public static void main(String[] args) {
	//简单工厂方法模式
	//先创建工厂(创建工厂对象)
	ComputerFactory1 factory=new ComputerFactory1();//通过工厂类创建对象   
    //再让工厂生产电脑(创建电脑对象)
	Computer computer1=factory.produce("personalComputer");
	computer1.work();
	Computer computer2=factory.produce("workComputer");
	computer2.work();
	
	//静态方法工厂模式
	//直接找工厂生产电脑
	Computer computer=ComputerFactory2.produce("personalComputer");
    computer.work();

}
}

总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式

3.抽象工厂模式

工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,拓展性较好.

对于在工厂方法的基础上,对同一个品牌的产品有不同的分类,并对分类产品创建的过程

​ 比如:一个汽车产品 会分为不同的种类(比如:迷你汽车 , SUV汽车 )

/**
*mini汽车接口
**/
public interface MiniCar {
public void showInfo();
}

public class BMMiniCar implements MiniCar {
@Override
public void showInfo() {
System.out.println("这是宝马 mini汽车....");
}
}

public class ADMiniCar implements MiniCar{
@Override
public void showInfo() {
	System.out.println("这是奥迪 mini汽车....");
	
}
}

/**
*SUV汽车接口
**/
public interface SUVCar {
public void showInfo();
}

public class BMSUVCar implements SUVCar{
@Override
public void showInfo() {
	System.out.println("这是宝马SUV汽车.....");
	
}
}

public class ADSUVCar implements SUVCar{
@Override
public void showInfo() {
	System.out.println("这是奥迪SUV汽车......");
	
}
}

public interface CarFactory {//汽车生产工厂  可以生产两种型号的汽车   两条产品线
	//不同品牌的两种型号汽车
public MiniCar produceMiniCar() ;
public SUVCar produceSUVCar() ;
}

public class BMCarFactory implements CarFactory{
@Override
public MiniCar produceMiniCar() {
	return new BMMiniCar();
}
@Override
	public SUVCar produceSUVCar() {
		return new BMSUVCar();
	}
}

public class ADCarFactory implements CarFactory{//相同类型继承 不同类型实现;
//	一类事物是否定义为接口,看该类事物是否需要分类即扩展
	
	@Override
public MiniCar produceMiniCar() {
	
	return new ADMiniCar();
}
@Override
	public SUVCar produceSUVCar() {
		
		return new ADSUVCar();
	}
}



package abstractfactorymode;

/**
 * @Description:测试
 * @author yanjiamin
 * @date 2020年10月13日 下午3:52:18
 */
public class TestCar {
public static void main(String[] args) {
	CarFactory carFactory=new ADCarFactory();
	MiniCar car =carFactory.produceMiniCar();
	car.showInfo();
	
	//生产大众SUV汽车
	//创建 生产大众SUV汽车的工厂
	CarFactory carfactory=new DaZhongSUVCarFactory();
	//生产汽车
	SUVCar car2=carfactory.produceSUVCar();
	car2.showInfo();
}
}

总结:普通工厂模式, 工厂方法模式和抽象工厂模式的区别和用途

1.对于简单工厂模式(包括静态和非静态),用于生产同一结构中的任意产品,对于新增产品不适用.(比如:生产电脑,不能再生产其它如汽车产品)

2.对于工厂方法模式,在简单工厂模式的基础上,生产同一个等级结构中的固定产品,支持新增产品(比如:生产不同品牌的电脑,支持新增品牌)

3.对于抽象工厂模式,用于生产拥有相同类型(Mini,SUV)的不同种类(品牌),支持新增种类,不支持新增类型(比如:生产不同品牌的相同类型的电脑,支持新增拥有相同类型的品牌)

4.模版方法

定义

模版方法是一种行为模式,父类的一个方法定义:完成这个行为的步骤,但不具体实现细节,由子类完成各个步骤的实现.在创建子类对象时,最终的实现过程是取决于子类实现.(不同对象完成某一件事的表现不同)

模板方法的准备:

​ 1、继承关系

​ 2、父类是抽象类(AbstractClass) :抽象类实现了模板方法,定义了算法的骨架

​ 3、子类继承抽象类(ConcreteClass):实现抽象方法,完成完整的算法

以早上去学校举例,老师和学生的状态不一样

public abstract class AbstractPerson {
/**
 * 在抽象类中定义一个模版方法,是实现这个方法的基本骨架
 * 每一步骤由子类具体实现
 */
		 public void preparedSchool(){//模版方法:完成早上去学校这一行为的步骤
		        getUp();

		        dressing();

		        eat();

		    }
		    //起床
		    public abstract void getUp();
		    //穿衣服
		    public abstract void dressing();
		    //吃早餐
		    public abstract void eat();
	}
	



public class Student extends  AbstractPerson {
    @Override
    public void getUp() {
        System.out.println("学生起床了");
    }

    @Override
    public void dressing() {
        System.out.println("学生开始穿衣服了");
    }

    @Override
    public void eat() {
        System.out.println("学生开始吃早餐");
    }
}




public class Teacher extends  AbstractPerson {
    @Override
    public void getUp() {
        System.out.println("老师起床,7点半起床");
    }

    @Override
    public void dressing() {
        System.out.println("老师要衣服得体,穿工装");
    }

    @Override
    public void eat() {
        System.out.println("老师吃早餐。");
    }
}




package templatemethod;
/**
 * @Description:测试
 * @author yanjiamin
 * @date 2020年10月13日 下午6:16:46
 */
public class Test {
public static void main(String[] args) {
	 Student stu = new Student();
     stu.preparedSchool();

     Teacher teacher = new Teacher();
     teacher.preparedSchool();


}
}


二.内部类(inner class)

1.定义

在一个类中定义另一个类的代码结构,定义在类内部的类通常称为“内部类”,外面的类称为“外部类”,在逻辑关系上,内部类与外部类是从属关系,比如:一个People类中包含收货地址类(收货人,收货联系方式,…)

2.分类

2.1 普通内部类

​ 一个类A中定义另一个类B,其中类B就是类A的内部类,也是类A的一部分

​ 总结:

1.外部类的方法中,可以直接访问内部类的所有成员(包括私有)

2.内部类的方法中,也可以直接方法外部类的所有成员,当外部和内部的成员名相同时,就近原则访问成员,或者引入外部类的对象来访问外部类成员

2.2 静态内部类

​ 在普通内部类基础上,增加“static”关键字,与静态方法相似,满足静态的要求

总结:

1.在静态内部类的方法中,对于静态内部类中的静态方法可以直接通过 静态内部类类名.静态方法名 调用

2.在静态内部类的方法中,对于静态内部类中的非静态方法,需要创建静态内部类的对象才能访问

2.3 方法内部类

​ 在一个方法中定义的类,其中这个类只属于该方法,也只能在该方法中使用

注意:内部类生成的class文件 命名格式: 外部类名$内部类名.class

总结:

1.方法内部类中 可以直接使用外部类的成员

2.存在方法内部类的方法可以调用方法内部类里面的方法

public class People {
private String pname="张三";
int  age=18;
public void sayHello() {
	System.out.println("Let us say Hello");
	//外部类的方法中可以使用内部类的所有属性和方法
		Address address=new Address();
	    address.addressName="湖北武汉";
		address.contentName="李四";
		address.addressInfo();
}

//1.普通内部类   收货地址类
class Address{
	private String addressName;//收货地址
	private String contentName;//联系人
     int  age=20;
	public void addressInfo() {
		System.out.println("联系人:"+contentName+" 收货地址:"+contentName);
		//内部类的方法可以直接访问外部类的属性和方法
		System.out.println("可以访问外部类属性:"+pname);
		sayHello();
	}
	public void showAge(People people) {
		System.out.println("内部类age:"+age);
		System.out.println("内部类age:"+this.age);
		System.out.println("外部类age:"+people.age);
	}
}
//2.静态内部类  卡信息类
 static class Card {
	private static String cardNo="42000";
	private String cardName="身份证";
	//静态方法
	public static void cardShowInfo1() {
		System.out.println("静态内部类1"+cardNo);
	}
	//非静态方法
	public  void cardShowInfo2() {
		System.out.println("静态内部类2"+cardName);
	}
	
	public void method1() {
	        // 对于静态方法可以直接类名.方法名
	       Card.cardShowInfo1();
	        // 对于非静态方法,需要创建Card类的对象访问
		 Card card = new Card();
	        card.cardShowInfo2();
	}
}

 //3.方法内部类
 public void method3(){
     int score = 98;

     // 在这里定义一个类
    class MyClass{
        String subject="Java";
        public void getSubjectScore(){
            //方法内部类中 也可以使用外部类的成员
        	  sayHello();
            System.out.println(pname+"的"+subject+":"+score);
        }
    }

    //调用方法内部类里面的方法
    MyClass  mycls = new MyClass();
   // mycls.subject;
    mycls.getSubjectScore();
}
}

测试:
public class TestInnerClass {
public static void main(String[] args) {
	//1.普通内部类
	//创建外部类对象
	People people=new People();
	//创建内部类对象  必须依赖外部类对象
	People.Address address=people.new Address();
	//address不能访问私有属性
	address.addressInfo();
	address.showAge(people);
	
	//2.静态内部类
	People.Card.cardShowInfo1();
	//创建静态内部类对象
	People.Card card=new People.Card();
	card.cardShowInfo2();
	
	 // 3 .方法内部类
	//调用方法
    people.method3();

2.4 匿名内部类:

定义一个没有类名,只有对方法的具体实现的类.通常它依赖于实现关系(接口)或继承关系(父类)(匿名实现或者继承)

a、基于实现关系

public interface MyInterface {
    // 学习
    public void  study();
    //  工作
    public void work();
}

 // 创建一个匿名类(让接口的引用 指向匿名类的对象)
        MyInterface  person = new MyInterface() {
            @Override
            public void study() {
                System.out.println("这个人也好好学习");
            }

            @Override
            public void work() {
                System.out.println("这个人也好好工作");
            }
        };

        person.study();
        person.work();

b、基于继承关系

public class MyClass {

   public void service(){
        System.out.println("提供服务的方法。");
    }
}
// 父类 new 一个 匿名类,这个匿名类是它的子类
        MyClass cls = new MyClass(){
            @Override //匿名类重写父类的方法 service
            public void service() {
                System.out.println("这是子类的方法");
            }
        };
        cls.service();

三.异常

1.异常的概述

异常定义:程序在执行过程中,由于发生"不正常"事件,导致JVM非正常中断,使程序无法正常运行,称为异常.

生活中的异常:早上起床去上课,平时骑车20分钟可以到达教室,由于天气原因导致不能按时到达教室上课,此时就属于异常现象.

2.异常关键字

try: 试一试 ,将可能发生异常的代码使用try包裹 ,try和catch不能单独出现

catch : 捕获异常, 当发生指定的异常对象时,执行catch代码

finally:无论是否发生异常,都会执行这个语句块,异常之后的最终处理 ,不常用,多用于资源回收

throw:抛出异常

throws:声明异常

3.捕获异常和层次关系

捕获异常:当程序在运行时发生了异常,为了让程序正常执行,需要对异常捕获(catch),此过程称为捕获异常.

Java是面向对象语言,异常本身是一个类(Exception),当发生异常时就会创建异常对象,捕获的就是异常对象.

//1.发生异常后正确捕获异常  一个try+一个catch
	System.out.println("请输入一个数字");
	Scanner sc=new Scanner(System.in);
	//异常代码可能发生异常,当用户输入的是非数字时,会抛出异常对象
	try {//发生异常后,try里面的异常代码后面的代码不会执行
		System.out.println("try里面的代码");
		int n=sc.nextInt();//InputMismatchException:由于未知事件即输入不规范(当用户输入非数字时),可能会出现异常,需要进行处理
		if (n%2==0) {
			System.out.println(n+"是一个偶数");
		}
	} catch (Exception ee) {//捕获父类异常对象:发生的什么异常就捕获对应的异常对象,不能确定异常类时,可以使用父类Exception异常类
		System.out.println("输入不规范");//直接使用Exception类的缺点:异常不清晰
	}
	System.out.println("程序继续运行直到结束。。。。");
 //  2.抛出的异常 不能被一个catch正确捕获,  使用   一个try + 多个catch  格式
        try {
            int[] num = {1, 2, 3};
            System.out.println(num[1]); // 没有捕获该异常对象,JVM依然终止运行
            System.out.println(10/0);
        }catch(NullPointerException ee){
            System.out.println("这是空指针异常");
        }catch(ArrayIndexOutOfBoundsException  ee){
            System.out.println("数组下标越界异常");
        }catch(Exception ee){
            // 输出异常 堆栈消息  方便程序员排错(尽可能避免用户看见)
            ee.printStackTrace();
            System.out.println("系统繁忙!"+ee.getMessage());
        }
        System.out.println("程序结束");
	//3.try...finally结构
        try{//捕获异常  但异常代码后面的语句块不会执行
            System.out.println("请输入两个数 ,计算两个数相除");
            Scanner sc = new Scanner(System.in);
            int  num1 =  sc.nextInt();
            int num2 = sc.nextInt();
            double  s = num1/num2; // 可能出错
            System.out.println(" try里面结束,结果:"+s);
        }finally{
            System.out.println("无论是否发生异常,都会执行这个语句块,一般用于资源回收");
        }
//try...catch...finally结构

try {
            System.out.println("请输入两个数 ,计算两个数相除");
            Scanner sc = new Scanner(System.in);
            int num1 = sc.nextInt();
            int num2 = sc.nextInt();
            double s = num1 / num2; // 可能出错
            System.out.println(" try里面结束,结果:" + s);
        }catch(ArithmeticException ee){
            ee.printStackTrace();
            System.out.println("除数不能为0 !!");
        }catch(Exception ee){
            ee.printStackTrace();
            System.out.println("系统繁忙!!!");
        }finally {
            System.out.println("用于资源回收。");
        }

4.抛出异常

抛出异常时,底层可以往上层抛出异常,但是到了异常继承关系的最顶层不能再抛出,必须处理异常即对异常进行系统封装处理.

抛出异常的代码的后面的代码不会再执行.

/**
     * 根据下标访问数组元素
     * @param array
     * @param index
     * @return
     */
    public static int getEleByIndex(int [] array , int index){
         // 抛出异常: 可以在异常发生时 或发生之前 创建一个异常对象并抛出
        //  手动抛出一个异常  throw new 异常类([异常消息]);
        if(index <0 || index > array.length-1){
            //抛出异常
            throw new ArrayIndexOutOfBoundsException("你的下标越界了");
        }
        int n =  array[index];
        return n;
    }

public static void main(String[] args) {
          //数组
        int  [] array = {2,1,4,5};
        int index=4;
        // 定义方法访问下标的元素  此时会产生异常 并抛出给方法的调用者
        try {
            int num = getEleByIndex(array, index);
            System.out.println("访问的元素:" + num);
        }catch(ArrayIndexOutOfBoundsException ee){
            System.out.println(ee.getMessage());
        }
        System.out.println("结束。。。");

    }

5.异常分类

由于有些异常是不能直接抛出的 ,需要先声明才可以抛出.将异常分为两大类:

1、 编译期异常(check 异常或者检查异常):在编译期间检查异常,如果没有处理异常,则编译出错

对于编译期异常,要么try…catch…finally处理异常,要么通过throw关键字向上抛出异常同时调用者使用throws关键字声明要抛出的异常

 //创建一个文件类的对象
        File  file = new File("d:/aaa.txt");
         // 在写代码(编译之前)时 一定要处理的异常(try..catch 或者 throws),就是编译时异常 
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
//这里的IOException  就是 编译期异常,需要手动处理的

2、运行期异常(runtime 异常或者运行异常):在运行期间检查异常,编译期不被检测

对于运行期异常,要么try…catch…finally处理异常,要么通过throw关键字向上抛出异常

        // 在运行期间抛出异常  不需要事先处理的  NullPointException是运行异常
        String str=null;
        System.out.println(str.length());

Exception中常用的异常类

1.检查异常(check Exception)

​ IOException :IO操作

​ FileNotFoundException: 文件未找到异常

​ SQLException:

​ EOFException:读写文件尾异常

​ DateFormatException:日期格式化异常

​ SocketException:SocketException

  1. 运行异常(RuntimeException)

​ ArrayIndexOutOfBoundsException :数组下标越界异常

​ NullPointerException:空指针异常

​ ArithmeticException: 算术异常

​ NumberFormatException :数字格式化异常

​ ClassNotFoundException: 类没找到异常

​ ClassCaseException: 类转换异常

注意: 对于抛出检查异常,需要使用throws声明,对于抛出运行时异常,不需要使用throws声明

系统抛出异常或者自定义抛出异常,处理或者继续抛出异常给调用者.抛出的异常可以作为消息提示机制

6.自定义异常

1、为什么需要使用自定义异常

​ 在Java中每一个异常类都表示特定的异常类型, 例如 NullPointerException表示空指针 ArithmeticException表示算术异常, 但是sun公司提供的API中不可能将实际项目中的业务问题全部定义为已知的异常类 ,这就需要程序员根据业务需求来定制异常类,例如 用户注册,可以定义用户注册异常(RegisterException),分数不能为负数也可以定制异常(ScoreExcecption).

2、什么是自定义异常

​ 在开发中根据自己的业务情况来定义异常类 ,灵活性较高,且方便易用。

3、如何实现自定义异常

​ a、定义编译期异常类,创建一个类继承 java.lang.Exception ;

​ b、定义运行期异常类,创建一个类继承java.lang.RuntimeException;

4、案例分析:自定义异常应用

​ 要求: 模拟用户注册操作, 用户输入用户名 ,验证用户名是否存在,如果存在,则抛出一个异常消息 “亲,该用户已存在,不能注册” ,通过自定义异常提示消息

public class RegisterException  extends  Exception {
    public RegisterException(){

    }

    public RegisterException(String message){
        // 将message(可作为提示/反馈信息) 赋值给父类的构造器
        super(message); //  将message赋值给父类的 属性,可通过getMessage()方法获取

    }
}

public class TestRegister {
     // 模拟已存在的用户
    String []  users = {"袁魏巍","王麻子","王小花//全局

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入你要注册的用户:");
        String uname = sc.next();
        TestRegister obj = new TestRegister();//创建异常对象

        try {
            // 调用方法 
            obj.checkUserName(uname);//用户存在时抛出异常即执行catch语句块
            System.out.println("注册成功");
        } catch (RegisterException e) {
            System.out.println("注册失败");
            System.out.println(e.getMessage());
        }


    }

    /**
     * 检查用户是否存在
     * @param username
     * @return   true  表示通过
     *    异常表示不通过
     */
    public boolean  checkUserName(String username) throws RegisterException{
         // 使用foreach遍历
        /**
         *   for(数据类型 变量名  : 数组名/集合名 ){
         *        循环中的 变量名代表的就是数组的元素
         *   }
         */
        for(String  u : users){
            // 判断u是否与 username相等 ,相等说明用户存在,需要抛出异常
            if(u.equals(username)){
                throw new RegisterException("亲,"+username+" 已存在,不能注册");//抛出异常 且后面的代码不会执行
            }
        }
        return true;

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值