1.异常概述
-
异常举例
Throwable 所有异常和错误的父类
Error 错误 一般由操作系统反馈给JVM的,无法对错误进行处理,只能修改错误行代码
Exception 异常是由JVM虚拟机产生的,反馈给程序,处理后代码可以执行往下,如果没有处理结果和错误一样,最终也会导致程序结束运行
- 控制台可以看出
-
异常分类
Exception父类
编译时异常
运行时异常
package com.itheima._01异常概述; /** 目标:能够说出异常概念和异常体系 讲解: 1. 什么是异常 * 程序在运行或编译过程中出现的问题 2. 现实生活的异常举例 3. Java中的异常体系 小结: 1. 什么是异常:程序在运行或编译过程中出现的问题 2. 异常的继承体系 Throwable -- 所有异常和错误的父类 Error -- 错误 Exception -- 异常 3. 异常的分类 编译时异常 运行时异常 */ public class Demo011 { }
package com.itheima._01异常概述;
/**
目标:能够判断程序出现的问题是异常还是错误
讲解:
1. 异常和错误的区别
错误:一般是由操作系统反馈JVM的,无法针对错误进行处理
只能修改错误行的代码
异常:一般是JVM产生反馈程序,可以针对异常进行处理,处理之后
代码可以执行往下执行,如果没有处理结果和错误一样。
小结:
1. 如何判断程序出现的问题是错误还是异常?
查看控制台的异常信息,如果类名是以Exception结尾就是异常,否则其他都是错误。
*/
public class Demo012 {
public static void main(String[] args) {
// 定义数组
// java.lang.OutOfMemoryError: Java heap space
// 内存溢出错误:堆内存溢出。
// 4k * 4m
// int[] arr = new int[1024 * 1024];
// System.out.println(arr.length);
// java.lang.ArithmeticException: / by zero
// 数学运算异常:除数不能为零
System.out.println(100/0);
System.out.println("aa");
}
}
package com.itheima._01异常概述;
/**
目标:理解异常的产生过程
小结:
异常的产生过程
1. JVM执行到有问题的代码时会根据问题的原因找到对应异常类
2. 根据异常类创建异常对象,并将异常对象抛给方法调用者
3. 如果方法调用者没有对异常进行处理,则继续向上抛,直到抛给了JVM
4. JVM接收到异常对象之后会将异常信息输出并终止程序运行。
*/
public class Demo013 {
}
2.异常的产生过程
- 异常的产生过程
- JVM执行到有问题的代码时会根据问题的原因找到对应异常类
- 根据异常类创建异常对象,并将异常对象抛给方法调用者
- 如果方法调用者没有对异常进行处理,则继续向上抛,直接抛给了JVM
- JVM接收到异常对象之后会将异常信息输出并终止程序运行
- 先抛给调用者sout(arr[3]) 没有处理方式就然后抛给main方法jvm 最后在控制台
3.异常处理-JVM处理
-
将异常信息输出到控制台(异常类名,异常原因,异常位置)
-
package com.itheima._02异常处理_JVM处理; /** 目标:掌握JVM处理异常的方式 小结: JVM处理异常的方式 * 将异常信息输出到控制台(异常类名,异常原因,异常位置) * 退出JVM终止程序运行 */ public class Demo02 { }
4.异常处理-捕获处理
-
捕获处理异常格式
- try{}catch(异常类名 变量名){}
- try代码块:编写可能出现异常的代码
- catch代码块:编写处理异常的代码,只有当try代码块的代码出现异常了才会执行该代码块的代码
-
多catch捕获异常的格式
- try{} catch{}catch{}
-
Exception e 是父类
- ArithmeticException e 算术异常
- NullPointerException e 空指针异常
-
多catch捕获异常的注意事项
- 多个catch之间的异常类型如果没有子父类关系,则父类异常必须写在后面
- 如果没有继承关系,则没有顺序之分
-
package com.itheima._03异常处理_捕获处理; /** 目标:能够捕获处理异常 讲解: 1. 捕获处理异常格式 try{ } catch(异常类名 变量名){ } * try代码块:编写可能出现异常的代码 * catch代码块:编写处理异常的代码,只有当try代码块的代码出现异常了 才会执行该代码块的代码 小结: 1. 捕获异常的格式 try{ 可能出现异常的代码 } catch(异常类名 变量名){ 处理异常的代码 } */ public class Demo031 { public static void main(String[] args) { System.out.println(div(2)); } /* 捕获处理异常格式 try{ } catch(异常类名 变量名){ } */ public static int div(int num){ int result = 0; try { /* JVM内部会判断num是否为0,如果0,则内部会执行如下操作: 1. ArithmeticException e = new ArithmeticException("/ by zero"); 2. 将异常对象e抛给方法调用者 */ result = 100 / num; } catch (ArithmeticException e){ // e = new ArithmeticException("/ by zero"); System.out.println("进来了吗..."); } System.out.println("come here"); return result; } }
package com.itheima._03异常处理_捕获处理;
/**
目标:能够捕获多种类型的异常
讲解:
1. 多catch捕获异常的格式
try{
}catch(异常类名 变量名){
}...
catch(异常类名 变量名){
}.
2. 多catch捕获异常的注意事项
多个catch之间的异常类型如果有子父类关系,则父类异常必须写在后面。
如果没有继承关系,则没有顺序之分。
小结:
1. 多catch捕获异常的格式
try{
}catch(异常类名 变量名){
}...
catch(异常类名 变量名){
}.
*/
public class Demo032 {
public static void main(String[] args) {
System.out.println(div(2));
}
public static int div(int num){
int result = 0;
try {
/*
当JVM检测到num为0时,内部执行如下操作:
1. ArithmeticException e = new ArithmeticException("/ by zero");
2. 将异常对象e抛给方法调用者
*/
result = 100 / num;
// 定义字符串
String str = "abc";
/*
当JVM检测到str为null时,内部执行如下操作:
1. NullPointerException e = new NullPointerException();
2. 将异常对象e抛给方法调用者
*/
System.out.println(str.length());
// 定义数组
int[] arr = {1,2,3};
/*
当JVM检测到索引越界,内部执行如下操作:
1. ArrayIndexOutOfBoundsException e = new ArrayIndexOutOfBoundsException("3");
2. 将异常对象e抛给方法调用者
*/
System.out.println(arr[3]);
} catch (NullPointerException e){ // e = new NullPointerException();
System.out.println("2又进来了吗...");
} catch (ArithmeticException e){ // e = new ArithmeticException("/ by zero");
System.out.println("1进来了吗...");
} catch (ArrayIndexOutOfBoundsException e) { // e = new ArrayIndexOutOfBoundsException("3")
System.out.println("3又又进来了吗...");
} catch (Exception e) { // e = new ArrayIndexOutOfBoundsException("3")
System.out.println("4又又进来了吗...");
}
System.out.println("come here");
return result;
}
}
5.异常处理-声明和抛出
-
throw 关键字的作用和格式
- 作用:将异常对象抛给方法调用者 并结束当前方法的运行 后面有代码走不了
- 位置:使用方法体中
- 格式:throw new 异常类名(“异常原因”)
-
throws 关键字的作用和格式
- 作用:将异常标识出来报告给方法调用者 方法内部可能会出现的异常
- 位置:使用在方法声明中
- 格式:修饰符 返回值类型 方法名(参数列表) throws 异常类名1,异常类名2…{}
-
package com.itheima._04异常处理_声明和抛出; /** 目标:能够使用throw和throws关键字处理异常 讲解: 1. throw关键字的作用和格式 作用:将异常对象抛给方法调用者并结束当前方法的运行。 位置:使用方法体中 格式:throw new 异常类名("异常原因"); 2. throws关键字的作用和格式 作用:将异常标识出来报告给方法调用者方法内部可能会出现的异常,让调用者要注意处理异常。 位置:使用方法声明上 格式:修饰符 返回值类型 方法名(参数列表) throws 异常类名1,异常类名2...{ } 小结: 1. throw关键字的作用:将异常对象抛给方法调用并结束方法运行 2. throws关键字的作用:将方法中可能出现的异常标识处理告诉方法调用者,让调用者处理异常。 */ public class Demo04 { // 是你同事写的 public static void main(String[] args) { try { int result = div(0); System.out.println("result = " + result); }catch (ArithmeticException e){ System.out.println("捕获到了异常..."); } } // 方法是你写的 public static int div(int num) throws ArithmeticException,NullPointerException{ if (num == 0){ // 1. 创建异常对象 ArithmeticException e = new ArithmeticException("除数不能为零"); // 2. 将异常对象抛给方法调用者 throw e; } return 100 / num; } }
6.finally代码块
-
finally代码块的格式
- try{} catch(异常类名 变量名){}finally{}
-
finally代码的特点
- 只要代码执行流程进入了try,不管try代码块的代码是否有异常,该代码块的代码都会执行
-
finally代码的作用
- 用于编写释放资源的代码,比如关闭Io流
package com.itheima._05finally代码块; /** 目标:能够说出finally代码的特点和作用 讲解: 1. finally代码块的格式 try{ } catch(异常类名 变量名){ } finally{ } 2. finally代码块的特点 只要代码执行流程进入了try,不管try代码块的代码是否有异常,该代码块的代码都会执行 3. finally代码的的作用 * 用于编写释放资源的代码,比如关闭IO流,关闭连接 小结: 1. finally代码的特点和作用 用于编写释放资源的代码,比如关闭IO流,关闭连接 */ public class Demo05 { public static void main(String[] args) { System.out.println(div(0)); } public static int div(int num){ if (num > 0) { try{ int result = 100/ num; // result = 50 return result; } catch(Exception e){ System.out.println("捕获到异常"); } finally { System.out.println("finally代码块..."); } } return 100; } }
7.异常常用方法
- String getMessage();获得异常原因字符串
- String toString();获得异常类型和原因字符串
- void printStackTrace();打印异常的栈信息
- e.get…to…print方法
package com.itheima._06异常常用方法;
/**
目标:掌握异常常用方法
讲解:
String getMessage(); 获得异常原因字符串
String toString(); 获得异常类型和原因字符串
void printStackTrace();
打印异常的栈信息(使用频频最高)
小结:
1. 异常中常用方法有哪3个
getMessage
toString
printStackTrace
*/
public class Demo06 {
public static void main(String[] args) {
try{
/*
1. ArithmeticException e = new ArithmeticException("/ by zero");
2. throw e;
*/
int result = 100 / 0;
} catch(Exception e){
// 获得异常原因字符串
// System.out.println(e.getMessage());
// 获得异常类型和原因字符串
// System.out.println(e.toString());
// 打印异常栈信息
e.printStackTrace();
}
}
}
8.编译时和运行时异常
-
异常的分类:运行时 编译时
-
如何区分异常时编译时异常还是运行时异常
- 运行时异常:只要是RuntimeException及其子类异常都是运行时异常
- 编译时异常:除了运行时异常以外的所有异常
-
运行时异常和编译时异常的特点 (可以文档查看)
-
编译时:如果方法体中抛出编译时异常,则要求必须要处理,如果方法声明上声明的编译时异常,则要求调用者一定要处理 throws要抛出
-
运行时:如果方法体中抛出运行时异常则可以处理,也可以不处理
如果方法体声明上声明运行时异常则调用者可以处理,也可以不处理
-
-
为什么编译器对运行时异常管理如此松散?
-
因为运行时异常一般可以通过程序员良好的编程习惯避免
-
因为比如空指针或者越界 都可以通过if来判断来避免异常发生
-
package com.itheima._07编译时和运行时异常; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; /** 目标:能够理解运行时异常和编译时异常的特点 讲解: 1. 异常的分类 编译时异常 运行时异常 2. 如何区分异常是编译时异常还是运行时异常 运行时异常:只要是RuntimeException及其子类异常都是运行时异常 编译时异常:除了运行时异常以外的所有异常 3. 运行时异常和编译时异常的特点 编译时异常 如果方法体中抛出编译时异常则要求必须要处理 如果方法声明上声明编译时异常则要求调用者一定要处理 运行时异常 如果方法体中抛出运行时异常则可以处理,也可以不处理 如果方法声明上声明运行时时异常则调用者可以处理,也可以不处理 4. 为什么编译器对运行时异常管理如此松散? 因为运行时异常一般可以通过程序猿良好的编程习惯避免。 小结: 1. 运行时异常的特点: 可以处理,也可以不处理 2. 编译时异常的特点 必须要处理 */ public class Demo07 { public static void main(String[] args) { div(0); } public static int div(int num) throws ArithmeticException { int result = 0; if (num != 0){ // 运行时异常:创建异常对象并抛出给调用者 // throw new ArithmeticException("除数不能为零"); // 编译时异常 // throw new FileNotFoundException(); result = 100/num; } // 数组:ArrayIndexOutOfBoundsException 运行时异常 int[] arr = {1,2}; int index = 3; if (index < arr.length){ System.out.println(arr[index]); } // 字符串:NullPointerException 运行时异常 String str = null; if (str != null) { System.out.println(str.length()); } // 创建流 /*FileReader fr = new FileReader("a.txt"); fr.read(); fr.close();*/ return result; } }
-
9.异常处理的注意事项
针对编译型异常
- 父类方法没有声明异常时,子类重写父类方法时不能声明异常
- 父类方法有声明时,子类重写父类方法时可以声明和父类相同的异常及其子类异常
- 子类方法不能声明比父类声明大的异常
package com.itheima._08异常处理注意事项;
import java.io.FileNotFoundException;
import java.io.IOException;
// 子类
public class BaseStudent extends Student {
@Override
public void study() {
}
}
package com.itheima._08异常处理注意事项;
/**
目标:了解子类重写父类方法时异常处理注意事项(针对编译时异常而言)
讲解:
编译时异常一定要处理,运行时异常可以不处理
---- 我们以编译时异常演示
IOException
FileNotFoundException
父类方法没有声明异常时,子类重写父类方法时不能声明异常。
父类方法有声明异常时,子类重写父类方法时可以声明和父类相同的异常及其子类异常。
小结:
1. 子类重写父类方法时异常处理的注意事项
子类方法不能声明比父类方法声明大的异常
*/
public class Demo08 {
}
package com.itheima._08异常处理注意事项;
// 父类
public class Student {
public void study() {
}
}
11.自定义异常
-
步骤:
-
创建类继承Exception编译型或RuntimeException运行时
-
类名:XXXException
提供两个构造方法:
无参数构造:public XXXException{}
有参数构造:一个参数,用来接收异常信息
japackage com.itheima._09自定义异常; import java.util.Scanner; /** 目标:能够自定义异常 讲解: 1. 为什么要自定义异常? JDK提供的异常虽然很多,但是不一定符合我们的需求,此时我们可以根据 自己的业务来定义异常类。例如:年龄负数问题,考试成绩负数问题。 2. 自定义异常步骤 * 创建类继承Exception或RuntimeException * 类名:XxxException * 提供两个构造方法 * 无参数构造 * 有参数构造:1个参数,用来接收异常信息。 3. 自定义异常示例 模拟网站注册:用户输入用户名和年龄,判断年龄是否大于等于18, 如果没有则抛出自定义异常 小结: 1. 自定义异常的步骤 1.1 创建类继承Exception或RuntimeException:XxxException 1.2 提供两个构造方法 无参数构造:public XxxException(){ } 有参数构造:public XxxException(String message){ super(message);} */ public class Demo09 { public static void main(String[] args) { try{ // 创建键盘录入对象 Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String username = sc.nextLine(); System.out.println("请输入年龄:"); int age = sc.nextInt(); // 执行注册 if (register(username, age)){ System.out.println("注册成功"); } } catch(Exception e){ // System.out.println(e.getMessage()); e.printStackTrace(); } System.out.println("aaa"); } /** * 执行注册功能 * @param username 用户名 * @param age 年龄 * @return 成功返回true,否则false */ public static boolean register(String username,int age) throws No18AgeException { if (age < 18){ // 创建自定义异常对象 throw new No18AgeException("你还没满18岁,不能注册该网站...."); } return true; } }j
-
package com.itheima._09自定义异常;
// 创建类继承Exception或RuntimeException
public class No18AgeException extends Exception{
// 无参数构造方法
public No18AgeException(){}
// 有参数构造方法
// new No18AgeException("你还没满18岁,不能注册该网站....");
public No18AgeException(String message){
super(message);
}
}
12.并行和并发
- 线程引入:要下载两个文件,要求同时下载 :使用多线程
- 目的:让程序同时执行多个任务,提供程序执行效率
- 并行:在同一个时间点同时执行 一边吃饭 一边打电话
- 并发:在同一个时间段执行 先放下重复执行另一个打电话 在继续吃饭
package com.itheima._10并发和并行概述;
/**
线程引入
要下载两个文件:一个是文件A,一个是文件B,要求同时下载,如何实现?
需要使用到多线程
学习多线程的目的:让程序能够同时执行多个任务,提高程序执行效率。
目标:能够理解并行和发并
讲解:
1.并行: 在同一时间点同时执行,比如在15:15:20 同时执行A任务和B任务
比如:你在吃饭,电话来了,一边接电话一边吃饭
2.并发: 在同一个时间段执行,比如在15:15:20 到 15:15:30 同时执行A任务和B任务
比如:你在吃饭,电话来了,停下吃饭,去接电话,接完电话再接着吃饭
小结:
1. 什么是并行:同一时间点执行
2. 什么是并发:同一时间段执行
*/
public class Demo10 {
public static void main(String[] args) {
downloadA();
downloadB();
}
// A任务
public static void downloadA(){
System.out.println("下载文件A");
}
// B任务
public static void downloadB(){
System.out.println("下载文件B");
}
}
13.进程和线程
- 进程:一个正在进行的程序
- 线程:进程中的一个独立执行单元 是进程中一个独立执行路径
- 进程和线程比喻:
- 进程:工厂 进程本身不会执行代码
- 线程:工人
- 进程和线程的作用:
- 线程:用来执行代码,所有线程共享进程的资源
- 进程:用来封装线程,为线程执行任务提供资源(内存资源)
- 进程和线程的作用:
package com.itheima._11线程和进程概念;
/**
目标:能够说出进程和线程的概念
讲解:
1. 什么是进程
一个正在运行的程序
2. 什么是线程
进程中的一个独立执行单元
进程中的一个独立执行路径
3. 进程和线程比喻
进程:工厂
线程:工人
4. 进程和线程的作用
线程:用来执行代码,所有线程共享进程的资源。
进程:用来封装线程,为线程执行任务提供资源(内存资源)
小结:
1. 什么是进程:一个正在运行中的程序
2. 什么是线程:进程中的一个独立的执行路径
*/
public class Demo11 {
public static void main(String[] args) {
}
}
14.创建线程
-
Thread类介绍
- 是一个线程类,只要创建该类的对象就是一个线程(相当于招了一个工人)
-
创建线程的步骤
- 自定义类继承Thread类
- 重写run方法:将线程任务相关代码写在该方法中
- 创建自定义类的对象(线程对象)
- 调用线程对象的start方法开启线程
-
package com.itheima._12创建线程; /** 目标:能够使用Thread类创建线程 讲解: 1. Thread类介绍 是一个线程类,只要创建该类的对象就是一个线程(相当于招了一个工人) 2. 创建线程的步骤 1. 自定义类继承Thread类 2. 重写run方法:将线程任务相关代码写在该方法中 3. 创建自定义类的对象(线程对象) 4. 调用线程对象的start方法开启线程 小结: 1. 创建线程的步骤 1. 自定义类继承Thread类 2. 重写run方法:将线程任务相关代码写在该方法中 3. 创建自定义类的对象(线程对象) 4. 调用线程对象的start方法开启线程 */ public class Demo12 { public static void main(String[] args) { // 3. 创建自定义类的对象(线程对象): 相当于招了一个工人 MyThread t = new MyThread(); // 4. 调用线程对象的start方法开启线程:让工人干活 // 内部会触发run方法调用,只需要将线程任务的代码写在该方法中即可 t.start(); // 不能直接调用run方法:否则不会开辟新的执行路径 // t.run(); } }
package com.itheima._12创建线程;
/**
1. 自定义类继承Thread类
*/
public class MyThread extends Thread{
// 2. 重写run方法:将线程任务相关代码写在该方法中
@Override
public void run() {
System.out.println("线程任务代码...." + getName());
}
}
15.主线程和子线程
-
什么是主线程
程序启动时自动创建并执行main方法的线程
Java 程序启动时默认会创建两个线程,一个主线程,一个垃圾回收线程(后台线程)
-
主线程的执行路径
- 从main方法开始到main方法执行完毕
-
什么是子线程
- 除了主线程以外的所有线程都是子线程
-
子线程的执行路径
- 从run 方法开始直到run方法执行完毕
main是主 以外是子
package com.itheima._13主线程和子线程概述;
/**
目标:能够区分主线程和子线程
讲解:
1. 什么是主线程
程序启动时自动创建并执行main方法的线程
Java程序启动时默认会创建两个线程,一个主线程,一个垃圾回收线程(后台线程)
2. 主线程的执行路径
从main方法开始直到main方法执行完毕
3. 什么是子线程
除了主线程以外的所有线程都是子线程
4. 子线程的执行路径
从run方法开始直到run方法执行完毕
小结:
如何区分线程是主线程还是子线程?
获得线程名称,如果是main则是主线程,否则是子线程。
*/
public class Demo13 {
public static void main(String[] args) {
}
}
16.线程运行模式和原理
当计算机的cpu是单核时,在任意时刻只能执行一条机器指令,每个线程只有获得cpu的使用权才能执行指令
-
分时式模式:所有线程平均分配cpu使用权,每个线程使用cpu的时间相同
-
抢占式模式:java程序中的线程运行模式属于该种模式
cpu随机选择一个线程执行 所有线程一起抢夺cpu使用权,哪个线程抢到就先执行哪个线程的任务
-
同一个线程中代码时按顺序从上往下执行
-
所有线程共享进程的堆空间
-
每个线程都会有自己独立的栈空间
-
package com.itheima._14线程运行模式; /** 目标:掌握Java中的线程运行模式 讲解: 当计算机的CPU是单核时,在任意时刻只能执行一条机器指令, 每个线程只有获得CPU的使用权才能执行指令。 线程的运行模式 1. 分时式模式:所有线程平均分配CPU使用权,每个线程使用CPU的时间相同。 2. 抢占式模式:Java程序中的线程运行模式属于该种模式 CPU随机选择一个线程执行 所有线程一起抢夺CPU使用权,哪个线程抢到就先执行哪个线程的任务。 小结: 1. 线程的运行模式分为哪两种 分时式和抢占式 2. Java中线程运行模式属于哪一种 抢占式 */ public class Demo14 { }
-
原理
-
package com.itheima._15线程运行原理; /** 目标:理解多线程运行原理 讲解: 多线程的内存图解 小结: 多线程运行原理:CPU在多个线程之间来回切换调度,调度到哪个线程就执行哪个线程代码 */ public class Demo15 { public static void main(String[] args) { // 创建线程对象 MyThread t = new MyThread(); // 开启线程 t.start(); for (int i = 0; i < 10; i++) { System.out.println("main..."+i); } test(); } private static void test(){ System.out.println("test...."); } }
package com.itheima._15线程运行原理;
/**
1. 自定义类继承Thread类
*/
public class MyThread extends Thread{
// 2. 重写run方法:将线程任务相关代码写在该方法中
@Override
public void run() {
test();
for (int i = 0; i < 10; i++) {
System.out.println("run..."+i);
}
}
private void test(){
System.out.println("test....");
}
}
17.Thread类常用方法
package com.itheima._16Thread类常用方法;
/**
目标:掌握Thread类常用方法
讲解:
Thread类常用成员方法
public String getName(); 获得线程名称
public void setName(String name); 设置线程名称
public static void sleep(long millis);
* 让当前线程休眠指定的毫秒值
public static Thread currentThread();
* 用来获得执行当前方法的线程对象
小结:
1. 获取线程名称的方法
String getName()
2. 设置线程名称的方法
void setName(String name)
3. 获取当前线程对象的方法
static Thread currentThread();
4. 让当前线程休眠的方法
static void sleep(long time)
*/
public class Demo16 {
public static void main(String[] args) {
// 创建线程对象
MyThread t = new MyThread();
System.out.println("===="+t.hashCode());
// 设置线程名称
t.setName("下载文件A线程");
// 获得线程名称:Thread-序号
System.out.println(t.getName());
// 开启线程
t.start();
try {
// 让当前线程休眠1s:主线程
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
System.out.println("main..." + i);
}
// 获得主线程对象
Thread mt = Thread.currentThread();
// 获得主线程名称:main
System.out.println(mt.getName()); // main
}
}
package com.itheima._16Thread类常用方法;
/**
* @author pkxing
* @version 1.0
* @Package com.itheima._16Thread类常用方法
* @date 2019-08-07 16:39
*/
public class MyThread extends Thread {
@Override
public void run() {
try {
// 让当前线程休眠10毫秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Thread t = Thread.currentThread();
for (int i = 0; i < 10; i++) {
System.out.println("run..." + i);
}
}
}
18.实现Runnable接口创建线程
Thread类和Runnable接口相关的构造方法:Thread(Runnable target)
- 实现Runnable接口创建线程步骤
- 自定义类实现Runnable接口
- 重写Runnable接口的run方法,用来封装线程任务相关的代码
- 创建Runnable接口实现类对象,根据实现类对象创建Thread对象
- 调用线程对象的start方法开启线程
package com.itheima._17实现接口创建线程;
/**
目标:使用Runnable接口创建线程
讲解:
0. Thread类与Runnable接口相关的构造方法
* Thread(Runnable target)
1. 实现Runnable接口创建线程的步骤
* 自定义类实现Runnable接口
* 重写Runnable接口的run方法:用来封装线程任务相关的代码
* 创建Runnable接口实现类对象,根据实现类对象创建Thread对象
* 调用线程对象的start方法开启线程
2. 实现Runnable接口的好处
* 解决了类单继承的局限性
* 可以更好的在多个线程之间共享数据(卖票案例)
* 为线程池提供前提条件
小结:
1. 实现Runnable接口创建线程的步骤
1. 创建类实现Runnable接口并重写run方法:封装线程任务的代码
2. 创建接口实现类对象
3. 创建Thread类对象传递接口实现类对象
4. 调用Thread对象的start方法开启线程
*/
public class Demo171 {
/*
public class Thread {
private Runnable target;
public Thread(Runnable target){
this.target = target;
}
public void run(){
if (target != null) {
target.run();
}
}
}
*/
public static void main(String[] args) {
// 创建Runnable接口实现类对象
MyRunnable target = new MyRunnable();
// 根据实现类对象创建Thread对象
Thread t = new Thread(target);
// 调用线程对象的start方法开启线程
t.start();
}
}
package com.itheima._17实现接口创建线程;
/**
目标:理解实现Runnable接口的好处
小结:
实现Runnable接口创建线程好处
*/
public class Demo172 {
}
package com.itheima._17实现接口创建线程;
/**
自定义类实现Runnable接口
*/
public class MyRunnable implements Runnable {
// 重写Runnable接口的run方法:用来封装线程任务相关的代码
@Override
public void run() {
System.out.println("子线程run..." + Thread.currentThread().getName());
}
}
19.匿名内部类创建线程
- 匿名内部类预防回顾
- new 类名或接口名(){ }
- 使⽤线程的内匿名内部类⽅式,可以⽅便的实现每个线程执⾏不同的线程任务操作使⽤匿名内部类的⽅式实现Runnable接⼝,重新Runnable接⼝中的run⽅法:
package com.itheima._18匿名内部类创建线程;
/**
目标:了解匿名内部类创建线程的方式
讲解:
1. 匿名内部类语法回顾
new 类名或接口名(){
重写方法
}
小结:
匿名内部类创建线程的两种方式?
1. new Thread(){
public void run(){ }
}.start();
2. new Thread(new Runnable(){
public void run(){ }
}).start();
*/
public class Demo18 {
public static void main(String[] args) {
// 方式1:直接创建Thread类的子类对象
/*
class XxxThread extends Thread{
@Override
public void run() {
}
}
Thread t = new XxxThread();
*/
Thread t = new Thread(){
@Override
public void run() {
System.out.println("子线程..." + this.getName());
}
};
t.start();
// 简写格式:
new Thread(){
@Override
public void run() {
System.out.println("子线程..." + this.getName());
}
}.start();
// 方式2:直接创建Runnable接口实现类对象
Runnable target = new Runnable(){
@Override
public void run() {
System.out.println("run..." + Thread.currentThread().getName());
}
};
new Thread(target).start();
// 简化格式:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("run..." + Thread.currentThread().getName());
}
}).start();
}
}
20.总结
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
- 能够辨别程序中异常和错误的区别
异常:可以处理,处理之后程序可以继承运行
错误:无法处理,只能修改错误行代码
根据类名判断,如果是Exception就是异常,否则都是错误
- 说出异常的分类
编译时异常
运行时异常
- 说出虚拟机处理异常的方式
输出异常信息到控制台
结束程序运行
- 列举出常见的三个运行期异常
NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
- 能够使用try...catch关键字处理异常
try{ 可能出现异常代码 } catch(异常类名 变量名){ 处理异常代码 }
- 能够使用throws关键字处理异常
用在方法声明上:将异常标识处理告诉方法调用要注意处理异常
- 能够自定义异常类
1. 自定义类继承Exception或RuntimeException
2. 提供有参数和无参数构造方法
有参数构造:接收一个字符串,在方法中调用父类构造方法传递字符串
- 能够处理自定义异常类
* 方法内部处理:try{ 可能出现异常代码 } catch(异常类名 变量名){ 处理异常代码 }
* 调用者处理:
在方法体中使用throw关键字抛出异常
在方法声明上使用throws关键字声明异常
- 说出进程的概念:一个正在运行中的程序
- 说出线程的概念:进程中的独立执行路径
- 能够理解并发与并行的区别
并发:同一时间段执行
并行:同一时间点执行
- 能够开启新线程
实现接口方式
1. 自定义类实现Runnable接口:重写run方法
2. 创建实现类对象,根据实现类对象创建Thread类对象
3. 调用线程对象的start方法开启线程
- 能够描述Java中多线程运行原理
所有线程一起抢夺CPU,谁抢夺到就执行谁的代码。
- 能够使用继承类的方式创建多线程
1.自定义类继承Thread类,重写run方法
2.创建自定义类对象调用start方法开启线程
- 能够使用实现接口的方式创建多线程
1. 自定义类实现Runnable接口:重写run方法
2. 创建实现类对象,根据实现类对象创建Thread类对象
3. 调用线程对象的start方法开启线程
- 能够说出实现接口方式的好处
* 避免了Java类单继承的局限性
重点
1. 捕获处理异常
2. 声明和抛出处理异常
3. 掌握创建线程的方式:实现接口的方式
*/
记得点赞哦谢谢!加油ヾ(◍°∇°◍)ノ゙