Java零基础(十八)之异常+多线程的创建

  1. 异常

概述:程序的不正常执行
处理异常的必要性:如果不处理,程序则会中断

异常的分类:
Throwable:错误与异常的父类,子类有Error,Exception
Error: 错误异常,例如硬件问题,JVM异常,程序员无法处理
Exception:一般性异常,程序员能处理,包含两个子类:运行时和编译时异常
运行时异常:非受检异常,运行时出现问题,直接奔溃
例如:类型转换异常,下标越界,空指针异常,算数异常,输入不匹配异常,数字格式异常
编译时异常:受检异常, 编译时报错,需要再一次处理

1.1 运行时异常

public class RuntimeTest {
    
    
	public static void main(String[] args) {
    
    
		//运行时异常:
		Object o = "ss";  //向上转
		//Integer a = (Integer)o;  //向下转   类型转换异常  ClassCaseException
		
		int[] a= {
    
    1,2};
		//System.out.println(a[2]); //下标越界ArrayIndexOutOfBoundsException
		
		String s = null;
		//System.out.println(s.length()); //空指针异常NullPointerException
		
		//int i=1/0;  //ArithmeticException算数异常
		Scanner sc = new Scanner(System.in);
		//int num = sc.nextInt();  //输入不匹配异常InputMismatchException
		
		String ss = "abc";
		//int aa = Integer.parseInt(ss); //数字格式异常NumberFormatException
		
		if(true) {
    
     //加个逻辑判断,后面的代码就可到达
			throw new RuntimeException("手动抛出运行时异常");//已经出错了,后面不能有代码,奔溃
			//return;   //正常结束,跳出函数体; 后面都不能有代码
		}
		
		System.out.println("最后的执行。。。");
		
	}
}

1.2 编译时异常

//编译时异常:  编译时不通过,让你给出处理方案
//解决方案: 抛出,当前方法中不处理,提交给上一级去处理,如果上级也不处理,直接奔溃
public class CheckTest {
    
    
	public static void main(String[] args) throws FileNotFoundException, ParseException {
    
    
		//编译时异常:
		//FileNotFoundException: 文件找不到异常
		FileInputStream fis = new FileInputStream("a.txt");
		
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String strDate="2108-09-09";
		//ParseException:解析异常
		System.out.println(sdf.parse(strDate));
	}
} 

1.3 异常传递

异常的传递:当方法的多级调用出现异常的情况
运行时异常传递:
结论:多级调用时,出现异常,则会向上传递,如果每个层次都没有处理,则会奔溃

public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		a();
		System.out.println("执行最后...");
	}

	private static void a() {
    
    
		System.out.println("a的调用");
		b();
	}

	private static void b() {
    
    
		System.out.println("b的调用");
		Scanner sc = new Scanner(System.in);
		int num = sc.nextInt();  //如果我们输入字符串,则会提示输入不匹配异常
	}
}

编译时异常传递

//编译时异常的传递:
public class Test2 {
    
    
	public static void main(String[] args) throws FileNotFoundException {
    
    
		a();
		System.out.println("执行最后...");
	}

	private static void a() throws FileNotFoundException {
    
    
		System.out.println("a的调用");
		b();
	}

	//throws FileNotFoundException:抛出异常,当前方法不处理,抛给上一级
	private static void b() throws FileNotFoundException {
    
    
		System.out.println("b的调用");
		
		FileInputStream fis = new FileInputStream("b.txt");
	}
}

1.4 异常处理

运行时异常处理

//1.运行时异常的处理:  捕获异常
//捕获:隔离异常,使得后续的程序正常执行
/*
 
 try{
    //视图抓取有异常的代码..
 }catch(Exception e) //有问题则捕获--隔离了
     //打印异常
 */

public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		try {
    
    
			int i=1/0;
		}catch(NullPointerException e) {
    
    
			System.out.println("空指针异常..");
			e.printStackTrace();
		}catch (ArithmeticException e) {
    
     //捕获并隔离了,异常解决了
			System.out.println("算数异常..");
			//e.printStackTrace();
		}
		System.out.println("执行最后代码...");
	}
}

编译时异常处理

编译时异常的处理:
1.抛出:弃之不管,抛给上一级,之前案例已说明
2.捕获:隔离异常,使得后续的程序正常执行

public class Test2 {
    
    
	public static void main(String[] args) {
    
    
		try {
    
    
			FileInputStream fis= new FileInputStream("b.txt");
		} /*catch (FileNotFoundException e) {
			System.out.println("文件未找到异常");
		}*/catch (Exception e) {
    
     //父类的捕获只能放后面,如果子类异常没有捕获到,那么父类一定会捕获
			System.out.println("父类捕获异常..");
		}
		System.out.println("最后的执行。。。");
	}
}

传递中的异常处理
传递中的异常处理:
1.在方法实现中的捕获,在方法捕获后面的代码不受影响
2.在main方法中的捕获,仅仅只是main方法后面不会受影响

public class Test3 {
    
    
	public static void main(String[] args) {
    
    
		try {
    
    
			a();  //上一级的捕获
		} catch (FileNotFoundException e) {
    
    
			System.out.println("main方法中,文件未发现异常");
		}
		
		System.out.println("main方法后面不会受影响");
	}

	private static void a() throws FileNotFoundException {
    
    
		/*
		try {
			FileInputStream fis = new FileInputStream("b.txt");
		} catch (FileNotFoundException e) {
			System.out.println("文件未发现异常");
		}*/
		FileInputStream fis = new FileInputStream("b.txt");
		
		System.out.println("a方法实现中的执行...");
	}
}

1.5 finally的使用

trycatchfinally使用
finally:最终的,搭配try或try.catch去使用的
结论:不论能否捕获住,最终都会执行finally中的代码
finay的优先级非常高,甚至比return还要高

public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		try {
    
    
			int i=1/0;
		} /*catch (NullPointerException e) {
			System.out.println("空指针异常");
		}*/
		catch (ArithmeticException e) {
    
    
			System.out.println("算数异常..");
			return;  //跳出函数体
		}finally {
    
    
			System.out.println("最终要执行的");
		}
		
		System.out.println("最后的代码...");		
	}
}

tryfinally使用

finally的用法:
当程序是死循环时,后面是不能执行代码的,但是我们可以使用tryfinally,
将后续要执行的代码放到finally中即可

finally应用场景:
io流的关闭资源,数据库资源关闭,锁资源释放

public class Test2 {
    
    
	public static void main(String[] args) {
    
    
		try {
    
    
			while(true) {
    
    
				System.out.println("一直执行的...");
			}
		} finally {
    
    
			System.out.println("最后执行的...");
		}
			
	}
}

1.6 自定义异常

自定义异常案例=

//自定义异常: 抛出单个对象,往往用在自定义异常中
//一般项目中可以根据需求设定异常类继承Exception或RuntimeException

//案例:录入学生的姓名和年龄,姓名要求小于6个长度,年龄小于50岁
//分析:编写学生校验的异常类继承Exception

//捕获与抛出的应用场景:
//抛出:程序的异常影响很大用抛出,例如银行金额账户等数据异常
//捕获:程序的异常影响不大用捕获,例如:上传一张图片,不符合规格


class StudentException extends Exception{
    
    
	public StudentException(String msg) {
    
    
		super(msg);  //将学生检测异常提示传给父类
	}
}

class Student{
    
    
	private String name;  //封装性
	private int    age;
	

	public void setName(String name) throws StudentException  {
    
    
		if(name.length()<6) {
    
    
			this.name = name;
		}else {
    
    
			//抛出单个对象,往往用在自定义异常中
			throw new StudentException("姓名长度必须小于6");
		}
		
	}

	public void setAge(int age) throws StudentException {
    
    
		if(age<50) {
    
    
			this.age = age;
		}else {
    
    
			throw new StudentException("年龄必须小于50岁");
		}
		
	}
	
	public String getName() {
    
    
		return name;
	}
	
	public int getAge() {
    
    
		return age;
	}
	
}

public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		Scanner sc = new Scanner(System.in);
		Student st = new Student();
		System.out.print("请输入学生姓名:");
		String name = sc.next();
		try {
    
    
			st.setName(name);
		} catch (StudentException e) {
    
    
			e.printStackTrace();
		}
		System.out.print("请输入学生年龄:");
		int age = sc.nextInt();
		try {
    
    
			st.setAge(age);
		} catch (StudentException e) {
    
    
			e.printStackTrace();
		}
		
		System.out.println("姓名:"+st.getName()+";年龄:"+st.getAge());
	}
}

异常中的重写

声明异常中的重写:
1.满足之前重写的要求:返回值类型,方法名,参数类型和父类完全一致,权限大于等于父类
2.再加入异常声明
注意:子类声明的异常不能大于父类

class Super{
    
    
	public void eat() throws NullPointerException {
    
    
		
	}
}

class Son extends Super{
    
    
	@Override
	public void eat() throws NullPointerException /*Exception*/ {
    
    
		
	}
}

  1. 线程基础
    进程概念:运行中的程序
    线程概念:是进程中的一条执行路径,往往一个进程中会有多条执行路径–多线程

案例:
迅雷—多任务同时下载

JVM从main方法入口开始执行,这就是一个执行路径,我们叫做主线程;
可以在主线程中,创建其他线程,我们叫做子线程

进程与线程的关系:
线程是cpu调度的基本单位,cpu切片切到谁就谁执行
一个进程可以包含多个线程,至少有一个线程
进程具有独立的资源空间,但是一个进程中的多个线程共享资源

线程的特点: 随机互抢资源

线程的组成:
cpu时间片: 由操作系统分配每个线程执行的时间

运行数据:
堆数据:实例化出来的线程对象
栈数据:线程引用指向实例化的对象

线程的逻辑代码

线程的创建方式1

在这里插入图片描述

//创建线程方式1: 创建一个类继承Thread
//案例:主线程和子线程,各打印200次(互抢资源方式)
//分析,1.创建线程继承Thread类,重写run方法,该方法就是子线程执行的区域
    //2.实例化子线程对象,调用run方法执行 
class MyThread extends Thread{
    
    
	@Override
	public void run() {
    
    
		for(int i=1;i<=200;i++) {
    
    
			System.out.println("子线程执行-->"+i);
		}
	}
}
public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		
		//线程的启动:
		//将当前线程对象放入线程组供cpu调度,当cpu调度到你,在内部调用run方法;
		//没有调度到你,则是就绪状态
		MyThread thread = new MyThread();  
		thread.start();
		//thread.start();  //实例化一个线程对象,多次start  不可以
		
		new MyThread().start();
		
		for(int i=1;i<=200;i++) {
    
    
			System.out.println("主线程执行-->"+i);
		}
		
	}
}

线程的创建方式2

//创建线程方式2:实现一个任务的方式
//案例:主线程和子线程,各打印200次(互抢资源方式)

//Task实现Runnable任务
class Task implements Runnable {
    
    

	@Override
	public void run() {
    
    
		for(int i=1;i<=200;i++) {
    
    
			System.out.println("子线程执行-->"+i);
		}
	}

}
public class Test2 {
    
    
	public static void main(String[] args) {
    
    
		Thread thread = new Thread(new Task());
		thread.start();
		
		for(int i=1;i<=200;i++) {
    
    
			System.out.println("主线程执行-->"+i);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_45682261/article/details/125146934