Day 05
第一章 异常
1.1 什么是异常
异常指的是程序在运行或者编译过程中,遇到的非正常的情况,最终会导致java虚拟机运行的停止。
异常不等同与语法错误,语法错误在编译阶段就无法通过
1.2 异常的体系
异常的根类是java.lang.Throwable
,它有两个子类,java.lang.Error
与kava.lang.Exception
。
- Throwable 我们说的异常,通常来说就是指Throwable异常,这类异常可以t通过修改代码来处理,且必须处理,否则会让程序运行停止。
- 编译时期异常(checked) 如日期的格式化异常
- 运行时期异常(runtime) 如数组越界
- throwable的常用方法:
public void printStacktrace()
打印异常的详细信息public String getMessage()
获取发生异常的原因
- Error 异常是无法处理的,只能尽量避免
- Error的原因可能是内存溢出、或是系统奔溃,无法处理
- Error的原因可能是内存溢出、或是系统奔溃,无法处理
1.3异常的产生过程解析
public static void main(String[] args) {
int [] arr = {1,2,3,4,5,6,7};
getSum(arr,7);
}
public static int getSum(int [] arr,int n ) {
return arr[n];
}
首先在调用getSum方法时出错 (1),由于它没有对异常进行处理,创建了一个异常对象,并将其传回main()中调用它的方法处(2),但是main()中也没有处理异常的机制 (3),异常继续传递给JVM(java虚拟机),JVM收到异常后,把异常对象的名称、内容、位置显示在屏幕上,并使程序运行停止;
箭头处为异常类型,因为这个异常是数组越界,是java中已知的异常类型,框中的7代表了引发异常的原因。
第二章 异常的处理
2.1 抛出异常:throw
thorw关键字用来抛出异常对象,在方法内部使用。
抛出异常的步骤:
-
新建一个异常对象,封装一些信息,如一些提示语句
-
用throw关键字将它抛出给调用者
格式
throw new 异常类型名(参数);
throw new ArrayIndexOutOfBoundsException("数组越界");
throw new NullPointerException("空指针异常")
异常的处理方法:
- 捕获(可以处理时,采用 try-catch 包裹可能出现异常的语句)
- 抛出(无法处理的时候) throw
public static void main(String[] args) {
int [] arr = {1,2,3,4,5,6,7};
getSum(arr,7);
System.out.println("end");
}
public static int getSum(int [] arr,int n ) {
if(n>= arr.length) {
throw new ArrayIndexOutOfBoundsException("数组越界啦");
}
return arr[n];
}//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 数组越界啦
2.2 Objects非空判断
public static <T> T requireNonNull(T obj)
:查看指定引用对象不是null。
它的源码:对null进行了抛出异常。
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
但是Object的一些静态方法,对空指针是容忍的,如equals方法。
2.3 声明异常throws
-
异常出现后,如果没有被捕获,则此方法必须声明异常throws,throws用在方法上,throw用在方法中,将异常抛出给调用者。
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常,可以一次抛出多个).
格式:
修饰符 返回值类 方法名(参数) throws 异常类型1,异常类型2
public static void main(String[] args)throws ArrayIndexOutOfBoundsException {
int [] arr = {1,2,3,4,5,6,7};
getSum(arr,7);
System.out.println("end");
}
public static int getSum(int [] arr,int n )throws ArrayIndexOutOfBoundsException,NullPointerException {
if(n>= arr.length) {
throw new ArrayIndexOutOfBoundsException("");
}
System.out.println("dsaasdasd");
return arr[n];
}
2.4 捕获异常 try catch
try catch只能配合使用,不能单独使用,但是可以一个try,有很多catch。
public static void main(String[] args)throws ArrayIndexOutOfBoundsException {
int [] arr = {1,2,3,4,5,6,7};
try{int b = arr[7];
}catch(ArrayIndexOutOfBoundsException s){
System.out.println("抓住了");
}
System.out.println("结束");
}
输出结果为:抓住了
结束
异常如果被catch捕获后(catch到,即使此时catch里面没有语句块对异常进行操作,例如将上述代码改成空的catch块,结果依然会输出 : 结束),之后的语句会继续进行,直至程序运行结束或者是碰到另一个异常。
2.5 finally代码块
程序在遇到异常时,会发生跳转,导致某些程序不执行,finally代码块在运行过程中,一定会被执行(不管异常是否出现,是否捕获)。
当只有在try或者catch中调用退出JVM的相关方法,此时finally才不会执行,否则finally永远会执行。
应用场景:打开某些文件流,不管运行是否正常,最终都需要关闭的时候。
格式:try{…}catch{…}finally{…}
public static void main(String[] args)throws ArrayIndexOutOfBoundsException {
int [] arr = {1,2,3,4,5,6,7};
try{int b = arr[7];
}catch(ArrayIndexOutOfBoundsException s){
System.out.println("抓住了");
}
finally {
System.out.println("执行了finally");
}
System.out.println("结束");
}
-
上面的代码,三个输出都会执行
-
如果此时try中内容改为
int b = arr[5];
输出结果为:执行了finally 结束
如果finally代码块中包含return关键词,会影响程序的运行,覆盖其他的return,例如像判断两个对象是否相等,如果相等则返回1,不相等返回-1,而在finally语句块加上return -1,则永远会返回-1。
2.6 异常注意事项
-
在try中,一旦遇到异常,即便后面被成功捕获了,try中异常后面的语句也不会被执行
-
对于运行期异常RuntimeException,被抛出时可以不处理。既不捕获也不声明抛出。而对于编译异常则必须声明或是用try catch包围它。
-
当一个父类的一些方法抛出一些异常,一个类继承自它,重写这些方法时,不可以抛出更多异常,但是可以少抛,或者不抛出。父类方法如果没有抛出异常,子类重写该方法时,不可以抛出异常,只能用try-catch捕获。但是子类的构造方法,可以比父类构造方法抛出更多的异常
-
采用try catch捕获异常是,catch里面的异常类型必须是子类异常在前,父类异常在后,如果子类在后,会被父类异常的catch所屏蔽
-
异常处理有三种方式:
- 一次捕获一次处理 try{…} catch{…}
- 一次捕获,多次处理(最常用):try{…}catch{…1…}catch{…2…}…catch{…n…}
- 多次捕获,多次处理:很多try,很多catch
第三章 自定义异常类
根据自己的需求,定制所需异常类。如建立一个学生类,当学生的年龄小于0时抛出异常,但是这种异常没有在JDK内部定义。
- 自定义一个编译期异常: 自定义类 并继承于
java.lang.Exception
。- 自定义一个运行时期的异常类:自定义类 并继承于
java.lang.RuntimeException
。
public class Day05 {
private static String [] a = {"first","second","third"}
public static void main(String[] args) {
try {
add("first");
}catch(MyException s) {
System.out.print("抓住了 ");
}
System.out.println("运行结束");
}
public static void add(String name) throws MyException {
for(String str : a) {
if(str.equals(name)) {
throw new MyException("已经被注册了");
}
}
System.out.println("注册成功");
}
}
//运行时期异常则应 extends RuntimeException
class MyException extends Exception{
public MyException() {
}
public MyException(String name) {
super(name);
}
}
//抓住了 结束了
第四章 多线程
4.1 并发与并行
- 并发指的是许多任务在一时间段内被执行
- 并行指任务在同一时刻同时进行
在CPU处理器中,一个内核在每个瞬间可以执行一段程序,对于单核的CPU无法进行并行计算,只能进行并发计算,核数越多,能够并行处理的程序也就越多。
4.2 线程与进程
-
进程 :是指一个内存中运行的应用程序,每个进程都有属于自己的独立空间,一个程序至少运行一个进程;进程是系统运行程序的基本单位
例如任务管理器,谷歌浏览器运行后,存在若干个进程
-
线程:进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。拥有多个线程的应用程序,称为多线程应用程序。
-
线程调度的类型:
- 分时调度 :即每个线程占用CPU的时间相同,轮流使用
- 抢占式调度:根据线程的优先级来确定使用CPU的顺序,如果优先级相同,则再同级中随机取一个线程运行(线程的随机性)。
我们在使用软件的时候不存在只能操作一种软件的情况,而实际上CPU的一个核只能在一瞬间进行一个进程,之所以宏观上我们认为很多软件能同时进行的原因是,一个核心会不断地在各个线程之间切换,时间非常非常短,从宏观上看,像是多个软件一起在运行。
4.3 创建线程类
Java中代表线程的是java.lang.Thread
类,所有的线程对象,必须是Threa类及其子类的实例。
每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。
创建与启动多线程的步骤:
- 自定义线程类,继承自Thread,重写run()方法,run()方法代表了线程要完成的任务—线程执行体。
- 创建线程对象,通过调用对象的start()方法来启动run()
- 采用Thread中
public final String getName()
的方法,可以获得该线程的名字
- 采用Thread中
public class Day05 {
public static void main(String[] args) {
NewThread newt = new NewThread("新线程");
newt.start();
for(int i = 0; i<15;i++) {
System.out.println("这是main线程"+i);
}
}
}
class NewThread extends Thread{
private String name;
public NewThread(String name) {
super(name);
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i =0;i<15;i++) {
System.out.println("这是: "+getName()+i);
}
}
}
//输出结果中两种线程的结果会交替出现