五、异常和线程
一、异常
java.lang.
-
Throwable:是所有错误或异常的超类
-
Error:错误
错误相当于程序得了一个无法治愈的毛病,必须修改源代码
-
Exception编译期异常,进行编译(写代码)java程序出现的问题
-
RuntimeException:运行期异常,java程序运行过程中出现的问题
异常相当于程序得了一个小毛病,把异常处理掉,程序可以继续执行
-
-
JVM检测程序会出现异常
JVM会做两件事:JVM中断处理
-
JVM根据异常原因创建一个异常对象,包含内容,原因和位置
-
如果没有异常处理逻辑(try...catch),JVM就会把异常抛出给方法的调用者main方法
main接收到这个异常对象,也没有处理逻辑就抛出给main方法的调用者JVM处理
JVM接收到这个异常对象,做了两件事1. 把异常对象以红色字体打印在控制台 2.终止现在正在执行的java程序
二、异常的处理
2.1 抛出异常throw
throw关键字
作用:
可以使用throw关键字在指定的方法中抛出指定的异常
使用格式:
throw new xxxException("异常产生的原因")
注意:
-
throw关键字必须写在方法内部
-
throw关键字后边new的对象必须是Exception或者Exception的子类对象
-
throw关键字抛出指定的异常对象,我们必须处理这个异常对象
throw关键字后面创建的是RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JVM处理
throw关键字后面创建的是编译异常,我们就必须处理这个异常,要么throws要么try...catch
throw new NullPointerException("传递对象为null");
2.2 Objects非空判断
Object obj = null;
Objects.requireNonNull(obj,"传递的对象为null");
2.3 声明异常throws
异常处理的第一种方式,交给别人处理
作用:
当方法内部抛出异常对象的时候,必须处理这个异常对象
可以使用throws处理异常,把异常对象交给调用者处理,JVM-->中断处理
使用格式:在方法声明时使用
修饰符 返回值类型 方法名(参数列表)throws XXXException,...{
throw new XXXException("产生原因");
}
注意:
-
throws关键字必须写在方法声明处
-
throws关键字后声明的异常必须是Exception或者是Exception的子类
-
方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常
如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可
- 调用了一个声明抛出异常的方法,我们就必须处理声明的异常
要么继续使用throws抛出,交给方法调用者处理,最终交给JVM
要么try...catch
public class Demo01Throwable {
public static void main(String[] args) throws IOException {
readFile("c://a.txt");
}
public static void readFile(String fileName) throws IOException {
if (!fileName.equals("c://a.txt")){
throw new FileNotFoundException("文件路径异常");
}
if (!fileName.endsWith(".txt")){
throw new IOException("文件的后缀名异常");
}
}
}
2.4 捕获异常try catch
try...catch:异常处理的第二种方式,自己处理异常
格式:
try{
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
异常的处理逻辑,一般在工作中,会把异常信息记录到一个日志中
}
注意:
-
try中可能会抛出多个异常,可以使用多个catch来处理
-
如果try中产生了异常,就会执行catch中的异常处理逻辑,执行完catch中的处理逻辑,就会执行之后的代码
如果try没有产生异常,就不会执行catch中异常处理逻辑,执行完try中的代码,继续执行try...catch后的代码
public class Demo01Throwable {
public static void main(String[] args){
try {
readFile("c://a.xt");
} catch (IOException e) {
System.out.println("catch.文件后缀不是.txt");
}
System.out.println("后续代码");
}
public static void readFile(String fileName) throws IOException {
if (!fileName.endsWith(".txt")){
throw new IOException("文件的后缀名异常");
}
}
}
Throwable类中定义了3个异常处理的方法
-
String getMessage()返回throwable的简短描述 -
String toString()返回throwable的详细信息字符串 -
void printStackTrace(PrintStream s)JVM打印异常对象,默认此方法,异常信息最全面
2.5 finally代码块
注意:
- finally不能单独使用,必须和try一起使用
- finally一般用于资源释放,无论程序是否异常,最后都要资源释放(IO)
2.6 多异常捕获处理
-
多异常分别处理
-
多异常一次捕获,多次处理
注意事项:
catch里面定义的异常变量,如果有子父类关系,那么子类异常变量必须写在上边
-
多异常一次捕获,一次处理
- 运行期异常可以不捕获也不处理 交给虚拟机处理
- finally中有return语句,永远返回finally的结果,避免该情况
- 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者父类异常的子类或者不抛出异常
- 父类方法没有抛出异常,子类重写父类方法时,也不能抛出异常,只能捕获处理
三、 自定义异常
自定义异常类:
java提供异常类,不够我们使用,需要自己定义一些异常类
格式:
public class XXXException extends Exception / RuntimeException{
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
注意:
1. 自定义异常类一般都是以Exception结尾,说明该类是一个异常类
2. 自定义异常类,必须继承Exception或者RuntimeException
1. 继承Exception,那么自定义异常类是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try catch
2. 继承RuntimeException,那么自定义异常类是一个运行期异常,无需处理,交给虚拟机处理(中断处理
1.继承Exception
public class MyException extends Exception {
public MyException(){
super();
}
public MyException(String s){
super(s);
}
}
public class Demo01Throwable {
//1.使用数据保存已经注册的用户名
static String[] userNames={"张三","李四","王五"};
//写在成员位置 方便都访问的到
public static void main(String[] args) /*throws MyException*/ {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入您要注册的用户名:");
String userName = scanner.next();
checkUserName(userName);
}
public static void checkUserName(String usrname) /*throws MyException*/ {
for (String userName : userNames) {
if (usrname.contains(userName)){
//true
try {
throw new MyException("该用户已经被注册了");
} catch (MyException e) {
e.printStackTrace();
return;//结束方法
}
}
}
System.out.println("恭喜您,注册成功");
}
}
2.继承RuntimeException
package com.dy.test;
public class MyException extends /*Exception*/ RuntimeException{
public MyException(){
super();
}
public MyException(String s){
super(s);
}
}
public class Demo02Throwable {
//1.使用数据保存已经注册的用户名
static String[] userNames={"张三","李四","王五"};
//写在成员位置 方便都访问的到
public static void main(String[] args) /*throws MyException*/ {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入您要注册的用户名:");
String userName = scanner.next();
checkUserName(userName);
}
public static void checkUserName(String usrname) /*throws MyException*/ {
for (String userName : userNames) {
if (usrname.contains(userName)){
//true
throw new MyException("该用户已经被注册了");//抛出运行期异常 无需处理 交给JVM处理 中断处理
}
}
System.out.println("恭喜您,注册成功");
}
}
四、多线程
4.1 并发与并行
并发:两个或多个事件在同一时间段内发生。cpu交替执行
并行:两个或多个事件在同一时刻发生(同时发生)。cpu同时执行

4.2 线程与进程
内存:所有应用程序都要进入到内存中执行 临时存储RAM
硬盘:永久存储ROM
点击应用程序执行,进入到内存中,占用一些内存执行,进入到内存的程序叫做进程
任务管理器-->结束进程
那么就把进程从内存中清除了

cpu:中央处理器,对数据进行计算,指挥电脑中的软件和硬件干活
cpu的分类:
AMD:
Inter:
线程是进程中的一个执行单元,负责程序的执行。

一个程序至少有一个进程,一个进程中包含多个线程
线程调度:
分时调度:
平均分配占用时间
抢占式调度:
优先级
4.3 创建线程类
单线程
主线程:执行主方法(main)的线程
单线程程序:java程序中只有一个线程
执行从main方法开始,从上到下依次执行
JVM执行main方法,main方法会进入到栈内存
JVM会找操作系统开辟一条main方法到cpu的执行路径
cpu就可以通过这个路径来执行main方法
而这个路径叫main(主)线程
public class Demo01MainThread {
public static void main(String[] args) {
Person p1 = new Person("小红");
p1.run();
Person p2 = new Person("小绿");
p2.run();
}
}
public class Person {
private String name;
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println(name+"-->"+i);
}
}
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
多线程
创建多线程程序的第一种方式:创建Thread类的子类
实现步骤:
-
创建一个Thread类的子类
-
在Thread的子类中重写Thread类的run方法,设置线程任务
-
创建Thread的子类对象
-
调用Thread类中的方法start()方法,开启新的线程,执行run方法
start()导致此线程开始执行;Java虚拟机调用此线程的
run方法。结果是两个线程同时运行:当前线程(从调用返回到
start方法)和另一个线程(执行其run方法)。不止一次启动线程是不合法的。 特别地,一旦线程完成执行就可能不会重新启动。
public class Demo01Thread {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 20; i++) {
System.out.println("main:"+i);
}
}
}
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run:"+i);
}
}
}
浙公网安备 33010602011771号