java异常相关内容
1.什么是异常?
程序在运行过程中出现的特殊情况
2.异常处理的必要性
任何程序都可能存在大量的未知问题、错误;如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。
3.异常分类
Throwable:可抛出的,一切错误或异常的父类,位于java.lang包中。
第一类:Error:JVM、硬件、执行逻辑错误、不能手动处理。
- 栈溢出 StackOverFlowError
- 堆(内存空间)溢出 OutOfMemoryError
public static void main(String[] args) {
//1 StackOverFlowError 栈空间溢出
method1();
byte[] arr=new byte[1024*1024*210];
}
public static void method1(){
System.out.println("helloworld");
method1();
}
程序运行设置堆大小当小于创建的数组时,出现堆溢出
public static void main(String[] args) {
//2 OutOfMemoryError 堆空间溢出
byte[] arr=new byte[1024*1024*210];
}
第二类:Exception:程序在运行和配置中产生的问题,可处理
[wppay]
- 运行时异常(不受检异常):RunntimeException及其子类:一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。
- 编译异常(受检异常):Exception中除RuntimeException极其子类之外的异常。如果程序中出现此类异常,比如说IOException,必须对该异常进行处理,否则编译不通过。在程序中,通常不会自定义该类异常,而是直接使用系统提供的异常类。
RunntimeException的主要异常:
运行时异常:
public class Demo2 {
public static void main(String[] args) {
//NullPointerException 空指针异常
String s=null;
System.out.println(s.hashCode());
//ArrayIndexOutOfBoundsException 数组越界异常
//ClassCastException 类型转换异常
Object integer1=new Integer("111");
String s2=(String)integer1;
//NumberFormatException
int n=Integer.parseInt("abc");
}
}
ArithmeticException
public class Demo3 {
public static void main(String[] args){
Scanner input=new Scanner(System.in);
System.out.println("请输入第一个数字");
int num1=input.nextInt();
System.out.println("请输入第二个数字");
int num2=input.nextInt();
int result=num1/num2;//ArithmeticException
System.out.println("结果是:"+result);
}
}
检查时异常:
//SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
//sdf.parse("2020-10-5");//ParseException 可以抛出去或try-catch
4.异常的产生
- 自动抛出异常:当程序在运行时遇到不符合规范的代码或结果,会产生异常
- 手动抛出异常:语法: throw new 异常类型("实际参数")
- 产生异常结果:相当于遇到return语句,导致程序因异常而终止
5.异常的传递
- 按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(可打印堆栈跟踪信息)并中断程序。
- 检查时异常:throws声明异常、修饰在方法参数列表后端
- 声明异常,向上抛出异常,由调用者去解决异常
- 调用者也可继续向上抛到JVM,没有处理
- 运行时异常:可处理可不处理,无需声明异常
6.异常的处理关键字
- try:可能出现异常的代码
- catch:捕获异常
- finally:异常最终处理,释放资源
- throw:抛出异常
- throws:声明异常
num++相当于另外开辟了一个变量存储
7.常见异常处理结构
7.1 try_catch(Ctrl+Alt+T)
- try{}catch{}
- try住可能出现异常的代码、catch异常处理的相关代码
- getMessage():获取异常信息,返回字符串
- printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void
- 三种情况
- 正常执行
- 出现异常并处理
- 异常类型不匹配
- try住可能出现异常的代码、catch异常处理的相关代码
public class Demo4 {
public static void main(String[] args) {
//(1)try{ } catch{ }
//出现三种清空
//1 没有异常发生
//2 发生异常
//3 异常类型不匹配(捕获的时候不匹配)
Scanner input=new Scanner(System.in);
int result=0;
try {
//可能发生异常的代码
System.out.println("请输入第一个数字");
int num1=input.nextInt();
System.out.println("请输入第二个数字");
int num2=input.nextInt();
result=num1/num2;
}catch (Exception e){
//捕获异常
//getMessage()获取异常信息
System.out.println(e.getMessage());
//打印栈的追踪信息
//e.printStackTrace();
}
System.out.println("结果是:"+result);
}
}
- try{}catch{}finally{}
- finally{}发生异常都会执行、可以释放资源等
- finally代码块不会被执行的情况
- 不执行的唯一情况,退出java虚拟机,System.exit(0);//退出jvm
- 程序所在的线程死亡或者cpu关闭
- 如果在finally代码块中的操作又产生异常,则该finally代码块不能完全执行结束,同时该异常会覆盖前边抛出的异常。
- try捕获到异常时,如果没有与之匹配的catch子句,则该异常交给JVM处理。如果存在finally,则其中的代码仍然被执行,但是finally之后的代码不会被执行。
- try没有捕获异常时,try代码块中的语句依次被执行,跳过catch。如果存在finally则执行finally代码块,否则执行后续代码。
- try捕获到异常时,如果存在与之匹配的catch,则跳到该catch代码块执行处理。如果存在finally则执行finally代码块,执行完finally代码块之后继续执行后续代码;否则直接执行后续代码。另外注意,try代码块出现异常之后的代码不会被执行。
public class Demo2 {
//try{ } catch{ } finally{ 不管有没有发生都会执行,释放资源 }
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int result = 0;
try {
System.out.println("请输入第一个数字");
int n1=input.nextInt();
System.out.println("请输入第二个数字");
int n2=input.nextInt();
result = n1/n2;
//System.exit(0);//退出jvm
} catch (ArithmeticException e) {
e.printStackTrace();
} finally {//不管有没有发生异常都会执行。特殊情况,jvm提前退出
System.out.println("释放资源");
}
System.out.println("结果:"+result);
}
}
- try{}catch{}catch{}….
- 子类异常在前,父类异常在后
- 发生异常时按顺序逐个匹配
- 只执行第一个与异常类型匹配的catch语句
- finally{}根据需要可写或不写
public class Demo3 {
//try{ } catch{ } catch{ } 注意:子类异常在前,父类异常在后
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int result = 0;
try {
System.out.println("请输入第一个数字");
int n1=input.nextInt();
System.out.println("请输入第二个数字");
int n2=input.nextInt();
result = n1/n2;
//System.exit(0);//退出jvm
} catch (ArithmeticException e) {
System.out.println("算术异常");
} catch (InputMismatchException e){
System.out.println("输入有误");
} catch (Exception e){
System.out.println("未知异常");
} finally {
System.out.println("释放资源");
}
System.out.println("结果:"+result);
}
}
- try{}catch{}catch{}finally{} 见面试题
- try{}finally{}
- 不能捕获异常、仅仅用来当发生异常时,用来释放资源。
- 一般用在底层代码,只释放资源不做异常处理,把异常向上抛出。
多重catch,遵循从小到大的顺序,父类异常在最后
public class Demo4 {
//try{...} finally{...} 不能处理异常,如果发生异常时,资源释放,同时异常向上抛出
public static void main(String[] args) {
try {
divide();
}catch (Exception e){
System.out.println(e.getMessage());
}
System.out.println("程序结束了");
}
public static void divide(){
Scanner input=new Scanner(System.in);
int result = 0;
try {
System.out.println("请输入第一个数字");
int n1=input.nextInt();
System.out.println("请输入第二个数字");
int n2=input.nextInt();
result = n1/n2;
//System.exit(0);//退出jvm
} finally {
System.out.println("释放资源");
}
System.out.println("结果:"+result);
}
}
面试题
try、catch、finally都可以包含return。但finally不建议使用,导致返回结果不正确。
在try中添加return方法,finally会不会执行? 会执行
- 即使try{}里有return语句,finally{}都会执行
- 没有异常发生先执行完finally(若finally里面有return语句直接返回,若没有再返回try的return)
- 有异常发生,先执行catch,再执行finally(若finally里面有return语句直接返回,若没有再返回catch的return)
7.2 throws
声明此类在有异常,自己不解决向上抛出异常,由调用者去解决异常,调用者也可继续向上抛到JVM,没有处理。
public static void divide() throws Exception
声明的是运行时异常,调用方可以处理也可以不处理,编译时异常,必须处理
public class Demo6 {
public static void main(String[] args) throws Exception{
// try {
// divide();
// }catch (Exception e){
// System.out.println(e.getMessage());
// }
divide();
System.out.println("程序结束了...");
}
public static void divide() throws Exception{ //声明异常:告诉调用者有异常
Scanner input=new Scanner(System.in);
System.out.println("请输入第一个数字");
int n1=input.nextInt();
System.out.println("请输入第二个数字");
int n2=input.nextInt();
int result=n1/n2;
System.out.println("结果是:"+result);
}
}
7.3 throw
除了系统自动抛出异常外,有些问题需要程序员自己抛出异常,throw new Exception();
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。只要没有被try-catch就会一直向上抛出由JVM处理。
public class DemoThrow {
public static void main(String[] args) {
try {
int a = DemoThrow.div(4, 0);
System.out.println(a);
} catch (Exception e) {
System.out.println(e.getMessage() + " main");
}
}
public static int div(int a, int b) {
if (b == 0) {
throw new ArithmeticException("异常信息:除数不能为0"); // 抛出具体问题,编译时不检测
}
return a / b;
}
}
class Person {
private String name;
private int age;
private String sex;
public Person(String name, int age, String sex) throws Exception {
this.name = name;
this.setAge(age);
this.setSex(sex);
}
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) throws Exception {
if (age <= 0 || age > 120) {
//手动抛出异常
throw new AgeException("年龄不符合要求");
} else {
this.age = age;
}
}
public String getSex() {
return sex;
}
public void setSex(String sex) throws Exception {
if (sex.equals("男") || sex.equals("女")) {
this.sex = sex;
} else {
throw new SexException("性别不能符合要求");
}
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
public void eat() {
System.out.println("开始吃饭了...");
}
}
public class TestPerson {
public static void main(String[] args) {
try {
Person cancan = new Person("灿灿", 200, "神");
System.out.println(cancan.toString());
} catch (Exception e) {
// System.out.println(e.getMessage());
e.printStackTrace();
}
System.out.println("程序结束了");
}
}
7.4 自定义异常
- 需要继承Exception或Exception的子类,代表特定问题
- 异常类型名称望文生义,可在发生特定问题时抛出对应异常
- 生成全部的Exception重写方法
- 右击生成里的Override - java.lang.Exception
案例同throw:抛出明确的异常
public class AgeException extends Exception{
public AgeException() {
super();
}
public AgeException(String message) {
super(message);
}
public AgeException(String message, Throwable cause) {
super(message, cause);
}
public AgeException(Throwable cause) {
super(cause);
}
protected AgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
public class SexException extends Exception {
public SexException() {
}
public SexException(String message) {
super(message);
}
public SexException(String message, Throwable cause) {
super(message, cause);
}
public SexException(Throwable cause) {
super(cause);
}
public SexException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
7.5 带有异常声明的方法重写
- 子类继承父类
- 方法名、参数列表、返回值类型必须和父类相同
- 子类的访问修饰符符合父类相同或是比父类更宽
- 子类中的方法,不能抛出比父类更多,更宽的检查时异常
- 父类不抛,子类也不能抛
class Person {
public void eat() throw Exception{
System.out.println("开始吃饭了...");
}
}
public class Student extends Person {
@Override
public void eat() throw Exception(或其子类、不抛) {
System.out.println("学生开始吃北京烤鸭...");
}
}
[/wppay]