今天的学习内容:
一、异常Exception
二、多线程
一、异常
对异常的理解:异常是程序在编译和运行时期的不正常情况,最终导致JVM非正常停止。
在Java语言中万物皆对象,Java语言的工程师把常见的异常封装成了对象,方便开发者遇到问题去检查异常出现的原因作出改进。
为了方便开发者很快的识别这些异常,把常见的异常都在API文档列举出来了。
异常并不是指语法错误,异常可分为运行时出现的异常,和编译期间出现的异常 (这不是语法错误!)。语法错误编译不会通过
这样的异常有很多:
ArrayIndexOutOfBoundsException 索引越界时出现此异常
NullPointerException null(null即对象未创建或没有得到引用地址)作为对象去调用方法,或者访问成员变量,访问调用数组的。
...
异常的体系
Throwable类
-
Error(错误)
很严重的错误,无法解决(如磁盘受损、系统崩溃)
-
Exception(异常)
编译时异常:Exception的子类或者间接子类(编译过程中会报红色波浪线提示,编译不会通过),编译异常必须解决
运行时异常:RuntimeException(时运行时异常的父类)的子类或者间接子类(运行时报错)
Throwable类的方法:
public String getMessage() // 返回异常的原因,打印在控制台
public String toString() //返回异常的详细信息,打印在控制台
public void printStackTrace() // 打印异常的详细信息(把异常对象的内容、原因、位置以红色字体打印在控制台)
throw关键字:
用于在特定条件下,产生(构造)一个异常对象。
作用:
编写API的工程师,为了让方法更加严谨,会对调用者传进来的参数做一些有效性的校验如果校验不通过,就会通过 throw 关键字产生一个异常对象,让调用者明白为什么错了。
处理异常的两种方式:
处理异常方式1:
- throws关键字:
在方法上声明异常,告诉调用者方法内部有异常(使用时请做相应处理)。调用者可以做异常处理(try-catch/也可以继续throws异常,抛出给该方法的调用者,如果是main方法也可以throws异常–>抛出给Java虚拟机)
throws异常的特点是出现执行到该异常所在的语句时就停止,不会继续执行后面的程序——即中断处理。
public static void method() throws 异常类{
.....方法里面有异常对象.....
}
【注意:throws只是用来声明编译时异常,运行时异常不需要声明,声明了也无所谓(多此一举)】
- 处理异常方式2:
try-catch处理异常,即解决异常。
try-cach保证出现异常,程序不会崩溃,即还是会继续执行其后续代码
try{
检查是否有异常
}catch(异常类1 e){
如果有异常就处理异常
}catch(异常类2 e){
如果有异常就处理异常
}
【注意:
1.try-cach捕获异常,产生的错误类型可以是对应的异常类型捕获或其父类类型异常来捕获,否则捕获失败,但所有子类异常都可以被父类异常exception全部捕获(所以在多异常处理中,子类异常放在父类异常之前)
2.一个try可以匹配多个cache,但只会捕获一个异常
3.try-catch处理异常特点:处理完异常之后,后续代码继续执行】
总结:
1)如果发现调用一个方法有红色波浪线(编译时异常)
使用try...catch处理(快捷键:alt+enter)
2)运行异常不需要处理,根据错误提示改代码即可
finally关键字:
必须与try或者try…catch一起使用
如果try语句块中有return语句,finally语句块中也有return,那么始终都是返回的是finally语句块中的结果
1)和try一起使用
try{
}finally{
//不管有没有异常方式,都会执行
//释放资源
}
2)try...catch一起使用
try{
}catch(异常类 e){
}finally{
//不管有没有异常方式,都会执行
//释放资源
}
自定义异常类
Java提供的异常类,不够我们使用,需要自己定义一些异常类
注意:
1.异常类最重要的就是类名(见名知意,通过名字就能描述异常信息)
2.自定义异常类一般都是以Exception结尾,说明该类是一个异常类
3.自定义异常类必须继承Exception或RuntimeException
- 继承Exception:那么自定义的异常类就是一个编译期的异常,如果方法内部抛出了编译期异常,就必须处理该异常,要么try-catch,要么throws
- 继承RuntimeException:那么自定义的异常类就是一个运行期异常,无需处理,交给虚拟机(中断处理)
如何写一个异常类
1)自定义一个类 extends Exception(编译时异常)/RuntimeException(运行时异常)
2)写两个构造方法即可(一个空参构造方法,一个带异常信息的构造方法)
1)自定义一个异常类:
package com.itheima.Exception;
public class FalseMoneyException extends Exception {
public FalseMoneyException() {
}
public FalseMoneyException(String message) {
super(message);
}
}
测试类:
try-catch方式处理异常:
package com.itheima.Exception;
public class Demo01 {
public static void main(String[] args) {
try {
sale(6);
} catch (FalseMoneyException falseMoneyException) {
falseMoneyException.printStackTrace();
}
System.out.println("交易结束");
}
/**
*
* @param money 指定钱的面值
* @throws FalseMoneyException 假钱异常,当钱的异常=6时,产生此异常
*/
public static void sale(int money) throws FalseMoneyException {
if(money==6){
throw new FalseMoneyException("不存在面额为"+money+"的纸币!");
}
if(money==10){
System.out.println("钞票读取成功....");
System.out.println("交易成功!");
}
}
}
运行结果:
交易结束//因为是try-catch方式处理异常,所以try-catch后面的代码任会执行
com.itheima.Exception.FalseMoneyException: 不存在面额为6的纸币!
at com.itheima.Exception.Demo01.sale(Demo01.java:21)//异常代码存在处
at com.itheima.Exception.Demo01.main(Demo01.java:6)
throws方式抛出异常:
package com.itheima.Exception;
public class Demo01 {
public static void main(String[] args) throws FalseMoneyException {
/*try {
sale(6);
} catch (FalseMoneyException falseMoneyException) {
falseMoneyException.printStackTrace();
}*/
sale(6);
System.out.println("交易结束");
}
/**
*
* @param money 指定钱的面值
* @throws FalseMoneyException 假钱异常,当钱的异常=6时,产生此异常
*/
public static void sale(int money) throws FalseMoneyException {
if(money==6){
throw new FalseMoneyException("不存在面额为"+money+"的纸币!");
}
if(money==10){
System.out.println("钞票读取成功....");
System.out.println("交易成功!");
}
}
}
运行结果:
//因为是throws抛出异常,所以不会执行 sale(6);下面的程序(即不会打印“交易结束”)
Exception in thread "main" com.itheima.Exception.FalseMoneyException: 不存在面额为6的纸币!
at com.itheima.Exception.Demo01.sale(Demo01.java:22)
at com.itheima.Exception.Demo01.main(Demo01.java:11)
/**
该注释是对下面的类或方法起解释说明作用
**/
程序的开发完成后都会生成一份应用说明文档(即API),idea有自动生成API文档的快捷功能,可以百度,不再赘述
二、多线程
并发和并行
- 并发:交替执行(同一时间段,单核CPU快速的在多个线程间来回切换(1/n毫秒)) 可以理解为并发是发生在单核CPU
- 并行:同时执行(同一时刻点,多核CPU同时处理多个线程),并行是发生在多核CPU中的吧,只是并行中线程被读取的概率更高而已
这里不用担心,多核CPU同时对多个线程来回读取,会不会出现同时读取到同一线程的问题?
不管单核也好,多核也好,其实给线程加上锁之后。进入锁之后同一时刻,只能有一个线程执行,那就不会年出现多个CPU执行同一个线程的问题(操作系统控制的)
进程和线程
- 进程:正在内存中执行的程序
- 线程:CPU执行进程的最小执行单元,一个进程可以包含个线程(多线程程序,进程的基本单元就是一个线程)
java.lang.Thread类:是描述线程的类,我们想要实现多线程,就必须继承Thread类
多线程的创建方式1:创建Thread类的子类
1)写一个子类 extends Thread
2)复写run方法
3)创建子类对象
4)调用start()开启线程
1).子类线程类继承线程父类(thread类)
package com.itheima.Thread;
public class DownloadThread extends Thread {
private String name;
@Override
public void run() {//run()方法是设置任务即线程的执行体,必须在子类中重写
for (int i = 1; i <= 100; i++) {
System.out.println(getName()+"....正在下载中.....已完成"+i+"%");
}
}
}
2)测试类中创建多个线程:
package com.itheima.Thread;
public class ThreadTest {
public static void main(String[] args) {
//创建一个线程对象
DownloadThread downloadThread1 = new DownloadThread();
downloadThread1.setName("波多野结衣老师");
downloadThread1.start();//启动线程
//再创建一个线程
DownloadThread downloadThread6 = new DownloadThread();
downloadThread6.setName("苍老师");
downloadThread6.start();//开启线程
//主线程方法(主线程优先级高一点)
for (int i = 1; i <= 100; i++) {
System.out.println("main主线程参与对CPU的资源争夺中......."+i+"次");
}
}
}
这里,不好意思上传运行效果了,可以自己搞一哈!
多次启动一个线程是非法的。特别是当前线程已经结束执行后,不能再重新启动。
Java属于抢占式调度,哪个线程的有限度高,就优先执行哪个线程,同一个优先级的线程,交替执行
Java学习第17天内容链接:
https://blog.csdn.net/LJN951118/article/details/89290726