异常
异常
概念
- 指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
异常体系
Throwable(类)
|–Error(不可避免,非代码造成的。比如电脑进水了,电脑冒烟了)
|–Exception(编译时期异常,如果不解决就无法生成.class问卷)
|–RuntimeException(运行时异常,如果不解决,可以生成.class文件,但是运行时可能报错)
异常分类
-
运行时异常(只有在运行时我们才知道会发生什么错误)
-
编译时异常(在编译时就知道他可能会发生什么错误,会报红,必须解决)
运行时异常
* 空指针异常
* 角标越界异常(数组角标,字符串角标,集合角标)
* 类型转换异常 ClassCastException
* 数学异常 1/0
* NoSuchException
* 并发修改异常
编译时异常
*ParseException
处理异常
-
方式一 交给JVM虚拟机
-
方式二 自己处理
-
方式三 交给别人处理
产生异常的2种方式
-
1.代码写的有问题,不小心造成的。int num = 1/0;//JVM帮我们创建,但是我们只知道会报错,错误提示不友好
-
2.人为、故意产生一个异常。throw new RuntimeException(“异常提示信息”);使用throw创建异常的好处:发生异常后提示比较友好
对方法的形式参数进行非空校验
- public static T requireNonNull(T obj) :查看指定引用对象不是null
作用:提高代码的执行效率还有健壮性
源码
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
public static void registerEmail(String email){
//对参数进行非空校验,如果参数是null则会报错
Objects.requireNonNull(email,"邮箱不能为空");
String s = email.substring(0, email.indexOf("@"));
System.out.println(s);
}
异常处理的两种方式
- 1.在方法上声明throws 表示自己不处理,交个给该方法的调用者处理- - throws 只能写在方法上
-- throws 后面可以跟多个异常
– 如果编写的代码中会产生多个异常,那么我们可以直接throws Exception
- try…catch:try捕获异常,如果try中有多个语句,遇到异常,后面的语句不会执行。try…catch代码后面的会执行。注意:try和catch都不能单独使用,必须连用
Throwable的方法
-
printStackTrace();//将异常信息控制台
-
toString();//获取到的是字符串 格式 异常名:异常的提示信息比如 NullPointerException:邮箱不能为空
-
getMessage();//获取到的也是字符串,仅仅获取到了提示信息,比如邮箱不能为空
多异常捕获
面试题
a:请说说final,finally,finalize 的区别?
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义成final类型,例如,一段代码……
finally是异常处理语句结构的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,调用System.gc()可以提醒垃圾回收器回收垃圾。
b:finally 里面的代码永远会执行吗 ?
不一定,程序在执行fianlly前以外G掉
c: 假如在catch里面有 return,finally里面的代码还能被执行吗 ?
如果能,请问是在 第一个return前, 还是在第一个return后 ?
也许你的答案是在return之前,但往更细地说,我的答案是在return中间执行,请看下面程序代码的运行结果:
考点:
如果代码里有finally,那么finally里面的东西一定会被执行,即使之前return过了
只有return才能设置方法的返回值
public static int test1() {
int x = 1;
try{
return x;
}finally{
++x;
}
}
public static int test2() {
int x = 1;
try{
return x;
}finally{
return ++x;
}
}
public static void main(String[] args) {
System.out.println(test1());
System.out.println(test2());
}
d.说说throw和throws的区别
throw 是制造异常的一种方式,thorws是处理异常的一种方式
throws后面可以跟多个异常,只能定义在方法上,多个异常有逗号隔开
throw 只能跟一个异常对象
private static void d() throws Exception {
throw new Exception();
}
自定义异常编写步骤
- 创建一个类,继承Exception
- 添加构造方法
自定义工具类
- 1.创建包,工具类一般放在utils包下
- 2.创建类
- 3.构造方法私有化
- 4.编写方法,所有的方法都要被static修饰
练习
编写代码模拟用户注册,如果用户名已经存在,抛出自定义异常,异常信息显示:用户名已经被注册
public static void main(String[] args) throws Exception{
ArrayList<String> list = new ArrayList<>();
System.out.println("输入要添加的人名:");
Scanner sc = new Scanner(System.in);
while (true){
String input = sc.nextLine();
regest(list,input);
System.out.println("当前系统里的人有:"+list);
}
}
private static void regest(ArrayList<String> list,String str) throws Exception{
if(list.contains(str)){
throw new RuntimeException("您注册的用户名已经存在");
}else {
list.add(str);
}
}
异常注意事项
- try…catch…catch 这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。
- 运行时异常被抛出可以不处理。即不捕获也不声明抛出。如果finally有return语句,永远返回finally中的结果,避免该情况.
- 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
- 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出
线程
并行与并发
- 并发:指两个或多个事件在同一个时间段内发生。(同一时刻,只能有一件事)
- 并行:指两个或多个事件在同一时刻发生(同时发生)。
进程:
- 进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创
建、运行到消亡的过程。(数据从硬盘到内存的通道)
线程
- 线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。(数据从内存到CPU的通道)
线程调度
- 分时调度(时间片轮转)
所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间 - 抢占式调度
优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
##创建线程的第一种方式
- 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
- 创建Thread子类的实例,即创建了线程对象
- 调用线程对象的start()方法来启动该线程