转载请标明原文地址,后续会持续更新《从零开始学习》系列,数据结构和算法,Mysql和ssm框架。
如果有问题可以私信或者直接在文章下评论,大概晚上会回。
如果零基础的同学没有学习的大概方向也可以私信问我,发给你一些学习路线和一些B站的学习视频地址。
希望能为世界带来些微价值,peace!
异常
一、异常的概念
概念:程序在运行过程中出现的特殊情况。
二、异常的分类
Throwable:可抛出的,一切错误或异常的父类,位于java.lang包中。
-Error:JVM、硬件、执行逻辑错误,不能手动处理。
-Exception:程序在运行和配置中产生的问题,可处理。
-RuntimeException:运行中异常,可处理,可不处理。
-CheckedException:受查异常,必须处理。//在Exception中除了RuntimeException的所有子类都属于CheckedException。//在编译时会报错,必须处理。
//RuntimeException异常
public class TestRuntimeException {
public static void main(String[] args) {
m6();
}
//java.lang.NullPointerException//空指针异常
public static void m1(){
Object o = null;
o.hashCode();
}
//java.lang.ArrayIndexOutOfBoundsException//数组下标越界异常
public static void m2(){
int[] nums = new int[4];
System.out.println(nums[5]);
}
//java.lang.StringIndexOutOfBoundsException
public static void m3(){
String str = "abc";
System.out.println(str.charAt(5));
}
//java.lang.ArithmeticException//除数不能为0
public static void m4(){
System.out.println(3/0);
}
//java.lang.ClassCastException//类转换异常
public static void m5(){
Object o = new Integer(123);
Scanner input = (Scanner)o;
}
//java.lang.NumberFormatException//数字格式异常
public static void m6(){
new Integer("10a");
}
}
三、异常的产生//告诉有异常。
-
自动抛出异常:当程序在运行时遇到不符合规范的代码或结果时,会产生异常。
-
手动抛出异常:
语法:
throw new 异常类型(“实际参数”);
-
产生异常结果:相当于遇到return语句,导致程序因异常而终止。//除非有finaly,否则后面的语句不再执行。
//1、
RuntimeException e = new RuntimeException();//此刻仅仅是个普通对象
throw e;
//2、
//throw new RuntimeException();
public class TestThrowException {
public static void main(String[] args) {
Student s = new Student();
s.setAge(300);
System.out.println(s.getAge());
}
}
class Student{
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if(age > 0 && age <253){
this.age = age;
}else{
RuntimeException e = new RuntimeException();//此刻仅仅是个普通对象//1、
throw e;
//throw new RuntimeException();//2、
}
}
}
四、异常的传递
- 异常的传递:按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)。//JVM默认异常处理为打印堆栈跟踪信息。
- 受查异常:throws 声明异常,修饰在方法参数列表后端。
- 运行时异常:因可处理可不处理,无需声明异常。
public class TestTrasnferException {
public static void main(String[] args) {//m3、m2都没处理,默认处理异常(打印堆栈跟踪信息)
System.out.println("main - start");
try {
m1(2);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("main - end");
//method(1);
}
public static void m1(int n) throws Exception {
System.out.println("m1 - start");
m2(n);
System.out.println("m1 - end");
}
public static void m2(int n) throws Exception {
System.out.println("m2 - start");
m3(n);
System.out.println("m2 - end");
}
public static void m3(int n) throws Exception {//向上报告(告知了调用者,此方法可能产生的异常)
System.out.println("m3 - start");
if (n % 2 == 0) {
throw new Exception("打印菱形,行号必须为奇数!");//相当于遇到return语句,导致程序因异常而终止。后面的语句不再执行。
}
System.out.println("打印菱形");
}
}
五、异常的处理//干掉异常。
try{
//可能出现异常的代码
}catch{
//异常处理的相关代码,如:getMessage()、printStackTrace()
}finally{
//无论是否出现异常,都需执行的代码结构,常用于释放资源。
}
注意:
try…catch覆盖的范围
另外多重catch需要从小到大,父类类型写到最后。//没有直接继承关系时,catch的位置无所谓。
//我感觉每个程序都可以写一个try{}catch(Exception e){};
public class TestTryCatch {
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();
try{
int result = num1 / num2; //throw new ArithmericException("/ by zero")
System.out.println(result);
}catch(Exception e){//= new ArithmeticException();
//System.out.println("注意,除数不能为零!");//处理方案1(自定义处理)
//e.printStackTrace();//处理方案2(打印堆栈跟踪信息)
//System.out.println(e.getMessage());//处理方案3(单独获取Message作为异常原因)
}
System.out.println("程序结束");//遇到异常也会打印。
}
}
输出:
请输入被除数:
3
请输入除数:
0
程序结束
public class TestMoreTryCatch {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int result = -1;
try{
System.out.println("请输入被除数:");
int num1 = input.nextInt();
System.out.println("请输入除数:");
int num2 = input.nextInt();
result = num1 / num2;
}catch(ArithmeticException e){
System.out.println("除数不能为零!");
}catch(InputMismatchException e){
System.out.println("请输入有效整数!");
}catch(RuntimeException e){
System.out.println("未知的运行时异常,请联系管理员");
}catch(Exception e){
System.out.println("未知的受查异常,请联系管理员!");
}
System.out.println(result);//无论运行是否存在异常,都要打印结果
System.out.println("程序结束");//会输出
输出结果:
请输入被除数:
3
请输入除数:
0
除数不能为零!
-1
程序结束
六、自定义异常
- 需继承自Exception或Exception的子类,常用RuntimeException。
- 必要提供的构造方法:
- 无参构造方法
- String message参数的构造方法
public class TestDefinedException {
public static void main(String[] args){
Student student = new Student();
try {
student.setAge(1112);
} catch (AgeException e) {
e.printStackTrace();
}
try {
student.setSex("aaaa");
} catch (Exception e) {
System.err.println("性别输出有误");//转换为带红色的输出
}
}
}
//受查异常
class AgeException extends Exception{
public AgeException() {
}
public AgeException(String message) {
super(message);
}
}
//运行时异常
class SexMismatchException extends RuntimeException{
public SexMismatchException() {
}
public SexMismatchException(String message) {
super(message);
}
}
class Student{
private int age;
private String sex;
public int getAge() {
return age;
}
public void setAge(int age) throws AgeException {//可以为Exception,但是和抛出的异常一样为最好
if (age>0&&age<254){
this.age = age;
}else{
//抛异常
throw new AgeException("年龄的正确区间为1到253");//AgeException
}
}
public String getSex() {
return sex;
}
public void setSex(String sex) throws SexMismatchException{
if (sex.equals("男")||sex.equals('女')){
this.sex = sex;
}else{
//抛异常
throw new SexMismatchException("性别为男或女");
}
}
}
七、方法覆盖
带有异常声明的方法覆盖:
- 方法名、参数列表、返回值类型必须和父类形同。
- 子类的访问修饰符合父类形同或是比父类更宽。
- 子类中的方法,不能抛出比父类或接口更宽泛的异常。
public class TestOverrideExceptionMethod {
public static void main(String[] args) {
Super s = new Sub();
//s.method();
Printable p = new MyClass();
try {
p.print();
} catch (IOException e) {
e.printStackTrace();
}
MyClass mc = new MyClass();
try {
mc.print();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Super{
public void method() throws Exception{
System.out.println("Super - method()");
}
}
class Sub extends Super{
public void method() throws IOException , ClassNotFoundException, RuntimeException{//子类可以有多个异常,但是不能抛出比父类或接口更宽泛的异常。
System.out.println("Sub - method()");
}
}
interface Printable{
public void print() throws IOException;
}
class MyClass implements Printable{
@Override
public void print() throws IOException{
}
}
八、jvm储存区域,栈的解析
//栈帧结构
public class TestReturn {
public static void main(String[] args){
int result = m1();
System.out.println(result);
}
public static int m1(){
int a = 10;
try {
a = 20;
throw new RuntimeException();
}catch (Exception e){
a = 30;
return a;//return执行了两次,执行完finally后返回执行return返回30。
}finally {
a = 40;
}
}
}
//输出:30