异常
1.异常介绍
1.概述:代码出现了非正常的现象,在java中,异常都是一个一个的类
2.Java把所有的非正常情况分成两种:异常(Exception)和错误(Error),它们都继承Throwable父类。
3.Error错误:一般是指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断。通常应用程序无法处理这些错误,因此应用程序不应该试图使用catch块来捕获Error对象。在定义该方法时,也无须在其throws子句中声明该方法可能抛出Error及其任何子类
4.Exception分为两大类:
运行时异常 即程序运行时,发生的异常。
编译时异常即编程时编译器检查出的异常,Checked异常。
所有的RuntimeException类及其子类的实例被称为Runtime异常;不是RuntimeException类及其子类的异常实例则被称为Checked异常。
(RuntimeException即程序运行时发生的异常,编译时检测不到这种异常,程序运行后,抛出异常
Runtime异常则更加灵活,Runtime异常无须显式声明抛出,如果程序需要捕获Runtime异常,也可以使用try…catch块来实现)
public class Demo01Exception {
public static void main(String[] args) throws ParseException {
//错误Error -> StackOverflowError
//method();
//运行时期异常 -> ArrayIndexOutOfBoundsException
int[] arr1 = new int[3];
//System.out.println(arr1[4]);
/*
编译时期异常:
注意看:编译时期异常是我们代码写错了嘛?不是,当我们调用方法的时候
该方法底层给我们抛了一个编译时期异常,所以导致我们一调用此方法
一编译,就爆红了
当我们一旦触发了这个异常,jvm就会将异常信息打印到控制台上,给程序员们看
*/
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = "2000-10-10 10:10:10";
Date date = sdf.parse(time);
System.out.println(date);
}
public static void method(){
method();
}
}
2.异常出现的过程
3.创建异常对象
1.关键字:throw
2.格式: throw new 异常
public class Demo03Exception {
public static void main(String[] args) {
String s = "a.tx1t";
method(s);
}
public static void method(String s){
if (!s.endsWith(".txt")){
//故意创建异常对象,用throw说明此处有异常
throw new NullPointerException();
}
System.out.println("我要执行了");
}
}
4.异常处理方式
4.1 异常处理方式一 throws
1.格式:在方法参数和方法体之间位置上写
throws 异常
2.意义:处理异常
将异常往上抛
public class Demo04Exception {
public static void main(String[] args)throws FileNotFoundException {
String s = "a.txt1";
add(s);//添加功能
delete();//删除功能
update();//修改功能
find();//查询功能
}
private static void add(String s)throws FileNotFoundException {
if (!s.endsWith(".txt")) {
//故意创建异常
throw new FileNotFoundException("文件找不到");
}
System.out.println("我要执行了");
}
private static void find() {
System.out.println("查询功能");
}
private static void update() {
System.out.println("修改功能");
}
private static void delete() {
System.out.println("删除功能");
}
}
4.2 异常处理方式二 throws多个异常
1.格式:throws 异常1,异常2
2.注意:
如果throws的多个异常之间有子父类继承关系,我们可以直接throws父类异常
如果不知道多个异常之间是否有子父类继承关系,我们可以直接throws Exception
public class Demo05Exception {
public static void main(String[] args)throws /*FileNotFoundException,*//*IOException*/Exception {
String s = null;
add(s);//添加功能
delete();//删除功能
update();//修改功能
find();//查询功能
}
private static void add(String s)throws /*FileNotFoundException,*//*IOException*/Exception {
if (s==null){
//故意造异常
throw new IOException("IO异常");
}
if (!s.endsWith(".txt")) {
//故意创建异常
throw new FileNotFoundException("文件找不到");
}
System.out.println("我要执行了");
}
private static void find() {
System.out.println("查询功能");
}
private static void update() {
System.out.println("修改功能");
}
private static void delete() {
System.out.println("删除功能");
}
}
4.3 异常处理方式三 try catch
1.格式:
try{
可能出现异常的代码
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}
public class Demo06Exception {
public static void main(String[] args){
String s = "a.txt1";
try{
//int[] arr = null;
//System.out.println(arr.length);//NullPointerException
add(s);//添加功能
}catch (FileNotFoundException e){
System.out.println(e);
}
delete();//删除功能
update();//修改功能
find();//查询功能
}
private static void add(String s)throws FileNotFoundException {
if (!s.endsWith(".txt")) {
//故意创建异常
throw new FileNotFoundException("文件找不到");
}
System.out.println("我要执行了");
}
private static void find() {
System.out.println("查询功能");
}
private static void update() {
System.out.println("修改功能");
}
private static void delete() {
System.out.println("删除功能");
}
}
4.4 异常处理方式四多个 catch
1.格式:
try{
可能出现异常的代码
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}...
2.注意:
如果catch的多个异常之间有子父类继承关系,我们可以直接catch父类异常
如果不知道多个异常之间是否有子父类继承关系,我们也可以直接catch Exception
public class Demo07Exception {
public static void main(String[] args) {
String s = null;
/* try {
add(s);//添加功能
}catch (FileNotFoundException e){
System.out.println(e);
}catch (IOException e){
System.out.println(e);
}*/
/*try {
add(s);//添加功能
}catch (IOException e){
System.out.println(e);
}*/
try {
add(s);//添加功能
}catch (Exception e){
e.printStackTrace();//将详细的异常信息打印到控制台上
}
delete();//删除功能
update();//修改功能
find();//查询功能
}
private static void add(String s) throws FileNotFoundException, IOException {
if (s == null) {
//故意造异常
throw new IOException("IO异常");
}
if (!s.endsWith(".txt")) {
//故意创建异常
throw new FileNotFoundException("文件找不到");
}
System.out.println("我要执行了");
}
private static void find() {
System.out.println("查询功能");
}
private static void update() {
System.out.println("修改功能");
}
private static void delete() {
System.out.println("删除功能");
}
}
4.5 throw与throws的区别
区别一:throw 是语句抛出一个异常;throws 是方法抛出一个异常;
区别二:throws可以单独使用,但throw不能;
区别三:throw要么和try-catch-finally语句配套使用,要么与throws配套使用。但throws可以单独使用,然后再由处理异常的方法捕获
//如果一个方法没有捕获一个可查异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。
//也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
//下面方法的声明抛出一个 RemoteException 异常:
public class className
{
public void deposit(double amount) throws RemoteException
{
// Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
5.finally 关键字
1.概述:代表的是不管是否触发了异常,都会执行的代码块
特殊情况:如果之前执行了System.exit(0)终止当前正在执行的java虚拟机
2.使用:都是配合try...catch使用
try{
可能出现异常的代码
}catch(异常 对象名){
处理异常的代码-> 将来开发会将异常信息保存到日志文件中
}finally{
不管是否有异常,都会执行的代码
}
public class Demo08Exception {
public static void main(String[] args){
String s = "a.txt";
try {
add(s);//添加功能
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
System.out.println("我必须滴执行");
}
}
private static void add(String s)throws FileNotFoundException {
if (!s.endsWith(".txt")) {
//故意创建异常
throw new FileNotFoundException("文件找不到");
}
System.out.println("我要执行了");
}
}
public class Demo09Exception {
public static void main(String[] args) {
int result = method();
System.out.println(result);
}
public static int method() {
try {
String s = null;
System.out.println(s.length());//空指针异常
return 2;
} catch (Exception e) {
return 1;
} finally {
System.out.println("我一定要执行");
//return 3;
}
}
}
finally的使用场景:
1.关闭资源
2.原因:对象如果没有用了,GC(垃圾回收器)回收,用来回收堆内存中的垃圾,释放内存,但是有一些对象GC回收不了,比如:连接对象(Connection),IO流对象,Socket对象,这些对象GC回收不了,就需要我们自己手动回收,手动关闭
将来不能回收的对象new完之后,后续操作不管是否操作成功,是否有异常,我们都需要手动关闭,此时我们就可以将关闭资源的代码放到finally中
public class Test { public static void main(String[] args) { FileWriter fw = null; try { fw = new FileWriter("day13_exception_object\\1.txt"); fw.write("哈哈哈");//假如这里写失败或者写成功了 } catch (IOException e) { throw new RuntimeException(e); }finally { if (fw!=null){ try { fw.close(); } catch (IOException e) { throw new RuntimeException(e); } } } } }
6.抛异常时注意的事项
1.如果父类中的方法抛了异常,那么子类重写之后要不要抛?
可抛可不抛
2.如果父类中的方法没有抛异常,那么子类重写之后要不要抛?
不要抛
public class Demo10Exception {
public static void main(String[] args) {
}
class A{
public void method()/*throws Exception*/{
}
}
class B extends A{
@Override
public void method()/*throws Exception*/{
}
}
}
7.try catch和throws的使用时机
1.如果处理异常之后,还想让后续的代码正常执行,我们使用try...catch
2.如果方法之间是递进关系(调用),我们可以先throws,但是到了最后需要用try...catch做一个统一的异常处理
1.编译时期异常是必须要处理的,不处理爆红,没法往下写
a.throws
b.try…catch
2.运行时期异常我们一般不处理,一旦出现运行时期异常,肯定是代码写的有问题,我们直接修改代码细节就行啦
8.自定义异常
1.如何自定义一个异常
(1) 要继承一个异常类型
自定义一个编译时异常类型:自定义类继承 java.lang.Exception
自定义一个运行时异常类型:自定义类继承 java.lang.RuntimeException
(2) 建议大家提供至少两个构造器,一个是无参构造,一个是(String message)构造器。
(3) 自定义异常需要提供 serialVersionUID
2.注意:
(1) 自定义的异常只能通过throw抛出。
(2) 自定义异常最重要的是异常类的名字和message属性。当异常出现时,可以根据名字判断异常类型。比如:TeamException("成员已满,无法添加"); 、 TeamException("该员工已是某团队成员");
(3) 自定义异常对象只能手动抛出。抛出后由try..catch处理,也可以甩锅throws给调用者处理。
public class LoginUserException extends Exception{
public LoginUserException() {
}
public LoginUserException(String message) {
super(message);
}
}
public class Demo11Exception {
public static void main(String[] args) throws LoginUserException {
//1.定义一个用户名,代表已经注册的用户
String username = "root";
//2.创建Scanner对象,录入用户名
Scanner sc = new Scanner(System.in);
System.out.println("请您输入要登录的用户名:");
String name = sc.next();
//3.判断用户名是否和已经存在的用户名一致
if (name.equals(username)){
System.out.println("登录成功了");
}else{
throw new LoginUserException("登录失败了,用户名或者密码有问题");
}
}
}
1.定义一个类
2.如果继承Exception 就是编译时期异常
3.如果继承RuntimeException,就是运行时期异常
9.打印异常信息的三个方法
Throwable类中的方法:
String toString() :输出异常类型和设置的异常信息
String getMessage(): 输出设置的异常信息
void printStackTrace():打印异常信息是最全的:包括异常类型,信息,以及出现的行数等
public class Demo11Exception {
public static void main(String[] args) {
//1.定义一个用户名,代表已经注册的用户
String username = "root";
//2.创建Scanner对象,录入用户名
Scanner sc = new Scanner(System.in);
System.out.println("请您输入要登录的用户名:");
String name = sc.next();
//3.判断用户名是否和已经存在的用户名一致
if (name.equals(username)) {
System.out.println("登录成功了");
} else {
try {
throw new LoginUserException("登录失败了,用户名或者密码有问题");
}catch (Exception e){
//System.out.println(e.toString());
//System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
}
10.常见异常及其产生的原因
java.lang.NullPointerException //空指针异常,调用了未经初始化或者不存在的对象。
java.lang.ClassNoFoundException //指定类找不到,类的名称和路径加载错误,通常是试图通过字符串来加载某个类时可能引发异常。
java.lang.NumberFormatException //字符串转换为数字异常,字符串数据中包含非数字型字符。
java.lang.IndexOutOfBoundsException //数组下标越界异常,调用的下标超出了数组的范围。
java.lang.IllegalArgumentException //方法传递参数错误,在很多j2me的类库中的方法,在一些情况下会引发这样的错误,比如本该是正数的被写成了负数。
java.lang.ClassCastException //数据类型转换异常,强制类型转换类型不匹配时出现此异常。
java.lang.illegalaccessexception //没有访问权限,当程序要调用一个类时,但是当前的方法没有对该类的访问权限。
java.lang.SQLException //SQL异常,在执行sql语句时出现的各种异常。
java.lang.InstantiationException //实例化异常,指不能实例化对象而出现的异常。
java.lang.NoSuchMethodExceptioin //方法不存在异常,这个异常出现的原因有两个,第一,缺少某些jar文件;第二,某些jar文件有重复。
java.lang.arithmeticexception //数学运算异常,出现不符合定义的运算,例如除以零。