文章目录
异常
写在开头:
我编写本文的时候还有点模糊不清,写到一半又有了新的理解就是!!当我们用try-catch试图捕获异常的时候,写在try里的语句如果发生了异常,那么异常后面的语句将不再执行。进入catch里执行,finally一定在try的return语句前执行。若catch里处理了异常,则try-catch整体语句后的代码可以继续执行。
什么是异常?
异常是指程序运行出现意料之外、不想让它出现的情况。如果我们不处理,那么异常会导致程序无法正常运行/崩溃。
认识常见的异常和错误
ArithmeticException算术异常
package com.gj.exception;
import java.util.Scanner;
public class TestException {
public static void main(String[] args) {
//从键盘输入2个整数,求它们的商、和、差、乘积
Scanner input = new Scanner(System.in);
System.out.print("请输入第1个整数:");
int a = input.nextInt();
System.out.print("请输入第2个整数:");
int b = input.nextInt();
System.out.println("商:" + a/b);//当b=0的时候,发生ArithmeticException
System.out.println("和:" + (a+b));
System.out.println("差:" + (a-b));
System.out.println("乘积:" + a*b);
input.close();
}
}
ArrayIndexOutOfBoundsException数组下标越界异常
package com.gj.exception;
public class TestException2 {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
for(int i=1; i<=arr.length; i++){//正确的下标范围:[0, arr.length-1]
System.out.println(arr[i]);
}
}
}
NullPointerException空指针异常
package com.gj.exception;
public class TestException3 {
public static void main(String[] args) {
Student[] arr = new Student[3];//arr的元素全部都是null
for (int i = 0; i < arr.length; i++) {
//缺少 arr[i] = new Student();
arr[i].setName("学生" + i);
arr[i].setScore(90+i);
}
}
}
ClassCastException类型转换异常
package com.atguigu.exception;
public class TestException4 {
public static void main(String[] args) {
Object obj = new Object();
String str = (String) obj;//ClassCastException
}
}
StackOverflowError栈内存溢出错误
package com.gj.exception;
public class TestError {
public static void main(String[] args) {
m();
}
public static void m(){
// System.out.println("m方法");
m();//无条件递归
}
}
InputMismatchException输入不匹配
package com.gj.exception;
import java.util.Scanner;
public class TestException {
public static void main(String[] args) {
//从键盘输入2个整数,求它们的商、和、差、乘积
Scanner input = new Scanner(System.in);
System.out.print("请输入第1个整数:");
int a = input.nextInt();//输入非整数时
System.out.print("请输入第2个整数:");
int b = input.nextInt();
System.out.println("商:" + a/b);
System.out.println("和:" + (a+b));
System.out.println("差:" + (a-b));
System.out.println("乘积:" + a*b);
input.close();
}
}
Java中如何表示异常的呢?
Java通过API中Throwable类的众多子类描述各种不同的异常。因而,Java异常都是对象,是Throwable子类的实例,描述了出现在一段编码中的错误条件。当条件生成时,错误将引发异常。
Java异常类层次结构图:
Throwable类是 Java 语言中所有错误或异常的超类。Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。
Error是Throwable的子类,用于指示合理的应用程序不应该试图捕获的严重问题,是程序无法处理的错误。例如:VirtualMachineError (虚拟机错误),包含OutOfMemoryError(堆内存溢出), StackOverflowError(栈内存溢出错误)。
这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。
Exception类是Throwable的子类,是程序本身可以处理的异常。它指出了合理的应用程序想要捕获的条件。 对于Exception来说,咱们程序员的态度应该是:(1)能通过条件判断等代码避免的,就不要用try-catch(2)无法避免的用try-catch处理。
Exception又分为:
- RuntimeException:运行时异常又称为不受检异常(编译器不要求强制处置的异常),类及其子类表示“JVM 常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
- CheckedException:编译时异常又称为受检异常(编译器要求必须处置的异常)这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
处理异常机制
在Java应用程序中,异常处理机制为:抛出异常,捕获异常。
注意:只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw
语句抛出。类似地,只有此类或其子类之一才可以是 catch
子句中的参数类型。
通常,这些实例是在异常情况的上下文中新近创建的,因此包含了相关的信息(比如堆栈跟踪数据)。
异常处理之try-catch
语法格式:
try{
尝试执行xx代码,它们可能发生异常,也可能不发生异常
}catch(异常的类型 异常参数名){ //通常参数名都是e
对异常的处理代码
以及 打印异常信息的代码(目前我们把异常打印到控制台,后期做项目异常信息打印到日志文件),错误信息怎么打印是根据实际情况来定
}
举例:
使用try-catch处理InputMismatchException异常。
package com.gj.exception;
import java.util.InputMismatchException;
import java.util.Scanner;
public class TestTryCatch {
public static void main(String[] args) {
//从键盘输入2个整数,求它们的商、和、差、乘积
Scanner input = new Scanner(System.in);
int a = 0;
while(true) {
try {
//选中要放到try{}里面的语句,按快捷键Ctrl + Alt + T
System.out.print("请输入第1个整数:");
a = input.nextInt();//这句代码可能会发生异常,如果发生异常,try剩下的语句就不执行了
//如果没有发生异常,try{}中剩下的语句继续执行
break;//如果有异常,break不走
} catch (InputMismatchException e) {
// throw new RuntimeException(e);//用throw的话,表示继续抛,等于异常没有处理掉,而是换了一种类型
//System.err.println(e);//普通的错误信息打印,
// e.printStackTrace();//标准异常信息的打印,包含异常的类型,异常的堆栈跟踪信息
System.out.println("输入信息不对,这里需要一个整数!!!");
input.nextLine();//这里会把刚刚输入的所有信息读取掉,但是不接收,因为这些信息是错误的,不要的
}
}
int b;
while(true) {
try {
System.out.print("请输入第2个整数:");
b = input.nextInt();
if(b==0){
System.out.println("除数不能为0,请重新输入!");
}else{
break;
}
} catch (Exception e) {
System.out.println("输入信息不对,这里需要一个整数!!!");
input.nextLine();
}
}
System.out.println("商:" + a/b);
System.out.println("和:" + (a+b));
System.out.println("差:" + (a-b));
System.out.println("乘积:" + a*b);
input.close();
}
}
使用条件判断避免InputMismatchException异常。
package com.gj.exception;
import java.util.Scanner;
public class TestTryCatch2 {
public static void main(String[] args) {
//从键盘输入2个正整数,求它们的商、和、差、乘积
Scanner input = new Scanner(System.in);
int a;
int b;
while (true) {
System.out.print("请输入第1个正整数:");
if (input.hasNextInt()) {
a = input.nextInt();
if(a>0) {
break;
}else{
System.out.println("这里需要输入正整数!");
}
} else {
System.out.println("这里需要一个整数!!");
input.nextLine();//读取非int整数的垃圾数据
}
}
while (true) {
System.out.print("请输入第2个整数:");
if (input.hasNextInt()) {
b = input.nextInt();
if(b>0){
break;
}else if(b==0){
System.out.println("除数不能为0!!!");
}else {
System.out.println("这里需要输入正整数!");
}
} else {
System.out.println("这里需要一个整数!!");
input.nextLine();//读取非int整数的垃圾数据
}
}
System.out.println("商:" + a/b);
System.out.println("和:" + (a+b));
System.out.println("差:" + (a-b));
System.out.println("乘积:" + a*b);
input.close();
}
}
异常处理之finally块
语法格式:
try{
尝试执行xx代码,它们可能发生异常,也可能不发生异常
}catch(异常的类型1 异常参数名){ //通常参数名都是e
异常的处理代码
}catch(异常的类型2 异常参数名){ //通常参数名都是e
异常处理代码
}finally{
无论try中是不是发生异常,
也不管catch能不能抓住异常,
就算是try和catch中有return语句,
都必须执行的代码,放这里
}
举例:
先执行输出语句1,没捕获到异常不执行2,finally一定执行3。
package com.gj.exception;
public class TestFinally1 {
public static void main(String[] args) {
try{
System.out.println("1、没有异常");
}catch (Exception e){
System.out.println("2、发生异常");
} finally {
System.out.println("3、一定执行");
}
//13
}
}
先执行语句1,0不能是除数发生异常执行catch语句3,发生异常后的语句不执行了,但finally一定执行。
package com.gj.exception;
public class TestFinally2 {
public static void main(String[] args) {
try{
System.out.println("1、没有异常");
System.out.println(1/0);//发生异常
System.out.println("2、发生异常");
}catch (Exception e){
System.out.println("3、处理异常");
} finally {
System.out.println("4、一定执行");
}
//134
}
}
finally会在return结束方法前执行。
package com.gj.exception;
public class TestFinally3 {
public static void main(String[] args) {
try{
System.out.println("1、没有异常");
return;//结束方法 先检查有没有finally,有finally,先执行finally再结束当前方法
}catch (Exception e){
System.out.println("2、发生异常");
} finally {
System.out.println("3、一定执行");
}
//13
}
}
package com.gj.exception;
public class TestFinally4 {
public static void main(String[] args) {
System.out.println(getNumber(5));
/*
运行结果:
finally
1
*/
}
public static int getNumber(int a){
try{
if(a>0){
return 1;
}else{
return -1;
}
}catch (Exception e){
return 2;
}finally {
System.out.println("finally");
}
}
}
package com.gj.exception;
public class TestFinally5 {
public static void main(String[] args) {
System.out.println(getNumber(5));
/*
运行结果:
finally
3
*/
}
public static int getNumber(int a){
try{
if(a>0){
return 1;//把1放入操作数栈,准备返回,先去执行finally
}else{
return -1;
}
}catch (Exception e){
return 2;
}finally {
System.out.println("finally");
return 3;//又把3放入操作数栈,结束方法,返回3
//如果finally中有return语句,其他return语句都失效了,
//不要在finally中写return语句
}
}
}
package com.gj.exception;
public class TestFinally6 {
public static void main(String[] args) {
System.out.println(getNumber());
/*
运行结果:
finally
2
*/
}
public static int getNumber(){
int a = 1;
try{
a++;//a=2
return a;//a=2 先把a的值放入操作数栈,然后去执行finally
}catch (Exception e){
a++;
return a;
}finally {
System.out.println("finally");
a++;//a=3,这里并未写return语句,没有返回3
}
}
}
package com.gj.exception;
import java.util.Scanner;
public class TestFinally7 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
try {
System.out.print("请输入姓名:");
String name = input.next();
System.out.println("name = " + name);
} catch (Exception e) {
System.out.println("输入错误");
}finally {
input.close();
//一般编写资源释放代码,例如;流的关闭,网络连接的断开等
}
}
}
throws关键字
throws的作用
告知/声明 调用者当前方法中“可能”发生xx类型的异常,需要“调用者”处理。如果调用者不处理,也可以继续throws来声明抛出异常,只是一旦发生异常,就会导致程序崩溃。如果为了保证程序的健壮性,那么最终还是要靠try-catch处理的。
语法格式:
【①修饰符】 ②返回值类型 ③方法名(【④形参列表】)【⑤throws 异常类型列表(多个异常可用逗号隔开)】{
⑥方法体语句;
}
拓展throws对重写方法的要求
- 子类重写方法throws的异常类型 <= 父类被重写方法throws的异常类型,这个要求主要是针对编译时异常类型来说
- 对于运行时异常类型,不做任何要求
举例:
package com.gj.exception;
public class TestThrows {
public static void main(String[] args) throws InterruptedException {
printNumber();//main方法就得到了信息,可能发生InterruptedException
//它的选择也有两种(1)try-catch(2)继续摆烂,接着throws
}
//需求:希望实现每隔1秒打印1个数字,实现10,9,8,....1效果
//提前剧透:Thread.sleep(毫秒数) 1s = 1000ms
//throws表示声明一下,当前方法可能发生xx类型的异常,需要 调用者处理,谁调用谁处理,反正我自己不处理
public static void printNumber() throws InterruptedException {
for(int i=10; i>=1; i--){
System.out.println(i);
Thread.sleep(1000);
}
}
}
throw关键字
throw总是出现在方法体中,主动抛出一个Throwable类型的异常对象。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。
手动抛出一个异常对象,代替return语句,返回异常对象,异常信息给调用者。
package com.gj.exception;
public class Account {//银行账号
private String id;
private double balance;//余额
public Account(String id, double balance) {
this.id = id;
this.balance = balance;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Account{" +
"id='" + id + '\'' +
", balance=" + balance +
'}';
}
public void withdraw(double money){
if(money<0){
// System.out.println("取款金额不能为负数");
// return false;
//throw语句可以代替return语句,返回的是异常信息,不正常的信息
throw new IllegalArgumentException("取款金额不能为负数");
//Illegal:非法的,Argument:参数,Exception:异常
}
if(money >balance){
// System.out.println("余额不足!");
// return false;
throw new UnsupportedOperationException("余额不足!");
//Unsupported:不支持,Operation:操作,Exception:异常
}
balance -= money;
// System.out.println("取款成功!");
// return true;
}
public boolean save(double money){
if(money<0){
System.out.println("存款金额不能为负数");
return false;
}
balance += money;
System.out.println("存款成功!");
return true;
}
}
package com.gj.exception;
import java.util.InputMismatchException;
import java.util.Scanner;
public class TestAccount {
public static void main(String[] args) {
Account a = new Account("111111",5000);
Scanner input = new Scanner(System.in);
while (true) {
try {
System.out.print("请输入取款金额:");
double money = input.nextDouble();
a.withdraw(money);
System.out.println("取款成功!");
break;
} catch (InputMismatchException e) {
System.err.println("金额必须是整数或小数,不能是字符串");
input.nextLine();
} catch (Exception e) {
// e.printStackTrace();
System.err.println(e.getMessage());
}
}
input.close();
}
}
throws与throw的区别:
throws | throw | |
---|---|---|
使用位置 | 方法签名中 | 方法体语句中 |
作用 | 告知调用者该方法可能发生xx异常,需要调用者警惕,并且处理 | 手动抛出一个异常对象,代替return语句,返回异常信息。一旦它执行了,就表示异常发生了。 |
自定义异常
使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。
步骤:
- 创建自定义异常类:一般会选择继承Exception和RuntimeException,如果不要求调用者一定要处理抛出的异常,就继承RuntimeException。
- 抛出自定义异常:在方法中通过throw关键字抛出异常对象。
- 捕获自定义异常:如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
- 在出现异常方法的调用者中捕获并处理异常
class MyException extends Exception { // 创建自定义异常类
String message; // 定义String类型变量
public MyException(String ErrorMessagr) { // 父类方法
message = ErrorMessagr;
}
public String getMessage() { // 覆盖getMessage()方法
return message;
}
}
标签:Java,System,try,详解,println,习题,异常,public,out
From: https://blog.csdn.net/weixin_52176709/article/details/142965511