Throwable
Throwable(异常最顶端的类)
Error(服务器奔溃,数据库奔溃)
Exception(异常类)
RuntimeException(运行时异常,编写程序时,程序员犯的错)
出现异常解决思路:
1.出现异常去找上级解决
2.找上级解决相当于找任务的调用者,main 的调用者 JVM 处理
3.JVM 默认的处理方式:打印异常类,错误信息和错误发生的位置,直接停止程序
常见的异常
1.空指针异常 NullPointerException
2.角标越界异常 ArrayIndexOutOfBoundsException
3.算术异常 ArithmeticException
写出这些异常:
1.空指针异常
int[] array = new int[3];
System.out.println(array[4]);
2.角标越界异常
int[] array = new int[3];
array = null;
System.out.println(array[0]);
3.算数异常
System.out.println(10 / 0);
try…catch…finally
try 指测试异常代码
catch 指捕获异常信息
finally 指异常结束后要做的事
try.....catch 捕获异常的流程
1.函数中某句代码可能会发生异常
2.发生异常就会产生对应的异常对象
3.这个异常对象返回给调用者
情况1:没有对异常进行处理,这时就会把异常交给上级 JVM 去处理
JVM 就会使用默认的处理机制:打印异常类,错误信息和错误发生的位置,直接停止程序
情况2:调用者进行了异常处理(try..catch)
这时,返回的异常对象,会和 catch 进行匹配
匹配成功,则执行 catch 中的语句,程序继续运行
public class Demo {
public static void main(String[] args) {
TestException testException = new TestException();
try {
// 可能发生异常的代码
int num = testException.fun(10, 0);
System.out.println(num);
} catch (Exception e) {
// 捕获异常
// (ArithmeticException e) ArithmeticException e = new ArithmeticException("/ by zero");
// (Exception e) Exception e = new ArithmeticException("/ by zero");
//()中要放捕获的是什么异常
System.out.println("/ by zero");
}
}
}
class TestException{
// 除法,返回两个数的商
public int fun(int a, int b) {
// 这句产生异常?
// 发生异常一定会产生一个对应异常对象
// new ArithmeticException("/ by zero");
return a / b;
}
}
多 catch 处理异常
int[] array = new int[3];
try{
// 报越界异常,产生越界异常的对象
System.out.println(array[4]);
array = null;
System.out.println(array[0]);
System.out.println(10/0);
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (ArrayIndexOutOfBoundsException e) {
// 匹配 catch 的时候,有一个被匹配上是,其他 catch 就不会继续匹配下去
System.out.println("角标越界异常");
} catch (ArithmeticException e) {
System.out.println("/ by zero");
} catch (Exception e) {
// 注意:如果 catch 中要写 Exception 一定要放在最下面
System.out.println("写错了");
}
System.out.println("---");
finally
出现异常与否,不会影响到 finally 的执行
finally 一定会执行
finally 的作用:一般会用来关闭资源(关闭流/数据库等等)
注意:final finally finalize 的区别?
final finally finalize 无任何联系,没有对比性
final 类不能被继承,方法不能被重新,变量定义为常量
finally 异常处理的时候使用,不可单独写,可以和 try 直接连用
finalize()是一个方法,做垃圾回收的时候使用,系统需要时,自己进行调用
try {
System.out.println(10 / 0);
// 即使直接 return 方法, finally 也会执行
// 例外:直接关闭 JVM 虚拟机关了就不执行了 System.exit(0);
return;
} catch (Exception e) {
System.out.println("/ by zero");
} finally {
System.out.println("我还有一句话,不知当讲不当讲!");
}
System.out.println("--------");
安卓开发
客户端开发 直接使用 Exception e 来接收异常
JavaEE开发
服务器开发 一般会把异常记录下来,写成错误日志,回头查看
如果不记录,相当于把这个错误遗漏过去
int num = 10;
try {
num = 20;
System.out.println(7 / 0);
return num;
} catch (Exception e) {
// 捕获异常
num = 30;
// 建立一个返回路径,相当于有一个箱子
// 箱子中保存的是,要返回的值
// 不会马上 return,会看一下,有没有 finally
// 有 finally 就执行,但是不会更改已经在返回路径中的值
// 等 finally 执行完了.再完全 return
return num;
} finally {
num = 40;
// finally 只写关闭资源,写 return 没有
// 在 finally 中放 return ,会导致之前的返回值全部覆盖掉
// return num;
}
运行时异常和编译时异常
运行时异常(程序员犯的错)
编译时异常(为了可能发生的错误做的提前准备)
public static void main(String[] args) throws FileNotFoundException {
/*
* 编译时异常
*
* 准备读取该路径下的文件
* 系统不知道这个路径中有没有这个文件
* 需要提前询问一下,如果没有这个路径下的文件
* 编译时异常,是系统强制程序员需要处理的
* 处理方式1:添加 try...catch (自行进行处理)
* FileInputStream inputStream = new FileInputStream("wl.txt");
* 处理方式2:把异常抛给上级去处理(和自己没关系了)
* 把问题 抛给 main 函数,在 main 函数声明上添加 throws 要抛出的异常类名
*/
/*
* 处理方式1:
* try {
* FileInputStream inputStream = new FileInputStream("wl.txt");
* } catch (Exception e) {
* System.out.println("路径下无此文件!");
* }
*/
/*
* 处理方式2:
* public static void main(String[] args) throws FileNotFoundException(将异常抛给 main 函数)
*/
// FileInputStream inputStream = new FileInputStream("wl.txt");
}
Throwable
public static void main(String[] args) {
Exception exception = new Exception("这里可以写错误信息");
// 获取错误信息
// String message = exception.getMessage();
// System.out.println(message);
// toString 方法
// System.out.println(exception);
// 打印错误信息,错误位置,异常类的类名
exception.printStackTrace();
}
自定义异常
public class Demo {
public static void main(String[] args){
Persons person = new Persons();
person.setName("甲");
try {
person.setAge(130);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(person);
}
}
// 自定义异常类
// 重点:类名要见名知意,并且跟系统学习
class AgeOutOfBoundsException extends Exception{
/**
* 序列化时使用的 id
*/
private static final long serialVersionUID = 1L;
// 写无参和有参的构造方法
public AgeOutOfBoundsException() {
super();
}
public AgeOutOfBoundsException(String message) {
super(message);
}
}
class Persons {
private String name;
private Integer age;
public Persons() {
super();
// TODO Auto-generated constructor stub
}
public Persons(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
// throws 关键词在方法的声明上标识这个方法可能会抛出异常
// 谁调用这个方法,这个异常就抛给谁
public void setAge(Integer age) throws Exception {
// 需要在这个范围内,才给 age 赋值
if (age <= 120 && age >=0) {
this.age = age;
} else {
throw new AgeOutOfBoundsException("超出定义范围");
}
}
@Override
public String toString() {
return "[姓名:" + name + ", 年龄:" + age + "]";
}
}
例题:
// 无限输入整数 存放到集合中 打印 输入quit停止
// 希望在输入 字符串的时候 让程序也能继续运行
public class Demo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 创建集合
ArrayList<Integer> arrayList = new ArrayList<>();
int index = 1;
while (true) {
System.out.println("请输入第"+ index +"整数(输入 quit 时结束输入):");
// 接收输入数据
String string = scanner.nextLine();
if (string.equals("quit")) {
// 停止循环
break;
}
try {
// 字符串转数字
int parseInt = Integer.parseInt(string);
// 添加到数组中
arrayList.add(parseInt);
index++;
} catch (Exception e) {
System.out.println("请输入第"+ index +"整数(输入 quit 时结束输入):");
// 接收输入数据
string = scanner.nextLine();
}
}
System.out.println(arrayList);
// 循环结束打印一下
scanner.close();
}
}
//
class AllInteger extends Exception{
/**
*
*/
private static final long serialVersionUID = 1L;
}
抛出异常(throw)
编译异常:系统会强制你去处理,try 或者抛
运行时异常(RuntimeException)(除了运行时异常其他都是编译时异常)
1.抛出运行时异常,方法的声明上,可以不用 throws 来标识
2.可以不对运行时异常进行处理
不处理直接停止程序
处理程序可以继续执行
编写时,如果在方法中抛出运行时异常,说明如果发生了该异常,就需要停掉程序,让程序再执行下去没有意义!
例如:
输入两个数字进行运算,先通过 string 接受,当输入的不可以转换成 Integer 类型时,就会报异常
测试编译异常
try {
Test.test();
} catch (Exception e) {
e.printStackTrace();
}
class Test{
// 抛出编译异常
public static void test() throws Exception{
throw new Exception();
}
}
测试运行时异常
try {
Test.test();
} catch (Exception e) {
// 抛出编译异常
class Test{
// 抛出运行时异常
public void test2() {
throw new RuntimeException();
}
}
// 计算圆的面积
double area = Test.getArea(-1);
System.out.println(area);
class Test{
// 计算圆面积
public static double getArea(double r) {
// 如果半径小于等于0,接下去的运算将没有意义
// 这时可以抛出运行时异常,来停止程序,修改代码
if (r < 0) {
throw new RuntimeException("半径输入有误!");
}
return r * r * Math.PI;
}
}
继承中的方法重写异常
父类抛出编译异常,子类可以不抛出异常
class Father{
public void test() throws Exception{
}
}
class Son extends Father{
@Override
public void test() {
}
}
父类抛出编译异常,子类可以抛出异常
class Father{
public void test() throws Exception{
}
}
class Son extends Father{
@Override
public void test() throws Exception{
}
}
父类没有抛出编译异常,子类不可以抛出编译异常!
当子类重写父类方法时,调用了一个有异常的方法,只能用 try...catch 处理异常,不能抛出异常
class Father{
public void test(){
}
}
class Son extends Father{
@Override
public void test(){
try {
method();
} catch (Exception e) {
e.printStackTrace();
}
}
// 带异常的方法
public void method() throws Exception{
}
}
例题:
/*
* 获取数字的工具类
* 要求:从键盘输入 输入的是字符串要处理异常重新输入
*
* 封装一个有两个数的对象类
* 要求:类中有两个int数字 作为成员变量
*
* 封装自定义异常类
* 要求:类名表示除法除数不能为0
*
* 封装运算类
* 1.获取 两个数的对象
* 2.获取 要做的运算法则 加法或者除法
* 输入数字1是加法 2是除法(输入错误 要重新输入)
* 3.加法方法
* 4.除法方法(要求捕获异常 并抛出自定义异常)
* 5.根据运算法则 执行运算 并返回运算结果
* 除数如果是0 要重新输入数字
*
* 测试类:
* 对以上方法进行测试
*/
/*
* 封装一个有两个数的对象类
* 要求:类中有两个int数字 作为成员变量
*/
public class MyNum {
private int num1;
private int num2;
public MyNum() {
super();
// TODO Auto-generated constructor stub
}
public MyNum(int num1, int num2) {
super();
this.num1 = num1;
this.num2 = num2;
}
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
@Override
public String toString() {
return "[num1=" + num1 + ", num2=" + num2 + "]";
}
}
/*
* 获取数字的工具类
* 要求:从键盘输入 输入的是字符串要处理异常重新输入
*/
@SuppressWarnings("resource")
public class IntTools {
// 私有化构造方法
private IntTools() {
}
// 递归
public static int getIntNum() {
System.out.println("请输入一个数字");
Scanner scanner = new Scanner(System.in);
String string = scanner.nextLine();
try {
// 字符串转数字
int num = Integer.parseInt(string);
return num;
} catch (Exception e) {
// 再次调用本方法,进行数字的输入
return getIntNum();
}
}
// 循环
public static int getNum() {
System.out.println("请输入一个数字");
Scanner scanner = new Scanner(System.in);
String string = null;
while (true) {
string = scanner.nextLine();
try {
// 字符串转数字
int num = Integer.parseInt(string);
return num;
} catch (Exception e) {
System.out.println("请输入一个整数!");
}
}
}
}
public class IsNotZeroException extends Exception{
/**
*
*/
private static final long serialVersionUID = 1L;
// 构造
public IsNotZeroException() {
super();
}
public IsNotZeroException(String message) {
super(message);
}
}
/*
* 封装运算类
* 1.获取 两个数的对象
* 2.获取 要做的运算法则 加法或者除法
* 输入数字1是加法 2是除法(输入错误 要重新输入)
* 3.加法方法
* 4.除法方法(要求捕获异常 并抛出自定义异常)
* 5.根据运算法则 执行运算 并返回运算结果
* 除数如果是0 要重新输入数字
*/
public class Operation {
// 获取两个数的对象
public static MyNum getMyNum() {
// 构建这个 MyNum 对象需要两个数
int num1 = IntTools.getIntNum();
int num2 = IntTools.getIntNum();
MyNum myNum = new MyNum(num1, num2);
return myNum;
}
/*
* 获取 要做的运算法则 加法或者除法
* 输入数字1是加法
* 2是除法(输入错误 要重新输入)
*/
public static String getChooseMethod() {
System.out.println("输入数字1是加法 2是除法(输入错误 要重新输入)");
int num = IntTools.getIntNum();
// 判断数字返回要做的运算
if (num == 1) {
return "+";
} else if (num == 2) {
return "/";
} else {
return getChooseMethod();
}
}
// 加法
public static int sum(MyNum myNum) {
return myNum.getNum1() + myNum.getNum2();
}
// 除法
// 为什么这里抛出了一个异常,没写返回值不报错?
public static int division(MyNum myNum) throws IsNotZeroException {
try {
return myNum.getNum1() / myNum.getNum2();
} catch (ArithmeticException e) {
// 获取到这个异常了,但是不处理
// 交给方法的调用者去处理
// 抛出异常,交给调用者去处理
throw new IsNotZeroException("除数为0!");
}
}
/*
* 根据运算法则 执行运算 并返回运算结果
* 除数如果是0 要重新输入数字
*/
public static int getResultByOperationAndMyNum(String operact, MyNum myNum) {
// 判断操作符,做相应的运算
if (operact.equals("+")) {
return sum(myNum);
}
// 除法
try {
// 报了异常,除数是0的时候
// 需要重新输入那两个数
return division(myNum);
} catch (IsNotZeroException e) {
System.out.println(e.getMessage());
// 重新调用获取两个数对象的方法
MyNum newNum = getMyNum();
// 重新调用运算的方法,进行运算
return getResultByOperationAndMyNum(operact, newNum);
}
}
}
/*
* 测试类:
* 对以上方法进行测试
*/
public class Test {
public static void main(String[] args) {
operactStart();
}
// 封装运算开始的方法
public static void operactStart() {
// 获取运算符
String operact = Operation.getChooseMethod();
// 获取两个对象
MyNum myNum = Operation.getMyNum();
int resultByOperationAndMyNum = Operation.getResultByOperationAndMyNum(operact, myNum);
System.out.println(resultByOperationAndMyNum);
}
}
http://blog.csdn.net/huzongnan/article/list