javaSE(从0开始)day14

目录

Exception异常处理:

异常的基本概念

一、java异常:

1、方法一:约定返回错误码。例如,处理一个文件,如果返回0,表示成功,返回其他整数,表示约定的错误码:

2、方法二:在语言层面上提供一个异常处理机制。Java内置了一套异常处理机制,总是使用异常来表示错误。异常是一种class,因此它本身带有类型信息。异常可以在任何地方抛出,但只需要在上层捕获,这样就和方法调用分离了:

3、异常的种类:首先分为error(严重错误不是人为的)和Exception(异常):

4、异常又分为运行时异常和编译异常:

(1)运行时异常:非必要处理异常

(1.1)java.lang.NullPointerException: 空指针异常

(1.2) StringIndexOutOfBoundsException:下标越界异常

(1.3)java.lang.ArrayIndexOutOfBoundsException:数组下标越界

(1.4)java.lang.ArithmeticException:算术异常(除0异常)

(1.5)java.lang.NumberFormatException:格式异常

(1.6)ClassCastException:类型转换异常

 (2)编译时异常:IOException   UnsupportedEncodingException....除运行异常外都是编译异常

二、捕获异常:

1、捕获异常:必须处理异常(会报错)捕获异常使用try...catch语句,把可能发生异常的代码放到try {...}中,然后使用catch捕获对应的Exception及其子类:

2、多个catch 语句:可以使用多个catch语句,每个catch分别捕获对应的Exception及其子类。JVM在捕获到异常后,会从上到下匹配catch语句,匹配到某个catch后,执行catch代码块,然后不再继续匹配。简单地说就是:多个catch语句只有一个能被执行。try块中可以放法多个异常代码,并且异常无关联,处理机制不同 ,try块出现异常,会跳转导对应的catch块,执行catch块中的内容,执行完成后,不会再返回到原出现异常的部分,进行下面的内容 ,异常后的代码不会执行。

3、finally代码块:无论是否有异常发生,如果我们都希望执行一些语句,例如清理工作,怎么写?可以把执行语句写若干遍:正常执行的放到try中,每个catch再写一遍。例如:

(1)finally特点:

(1.1)finally语句不是必须的,可写可不写;

(1.2)finally总是最后执行。

4、注意事项:

(1)多个异常进行捕获需要注意顺序问题

(2)Catch捕获时自上而下进行异常的匹配,越是顶级的类,越要放到下面,写法遂循先子后父 /

(3) 再不然把多余的catch省略

三、抛出异常:

1、抛出异常的两种方式:

(1) throws声明异常: throws:声明异常,在方法上声明可能会出现的异常类型

(2)throw  抛出异常: throw:扔出异常对象,放在方法体内,一般和if判断配合使用 

2、异常的传递:当某个方法抛出了异常时,如果当前方法没有捕获异常,异常就会被抛到上层调用方法,直到遇到某个try ... catch被捕获为止。

 3、异常的转换:在捕获异常的时候catch代码块里面又出现了一个新的异常,将新的异常信息传递给旧的异常信息。

4、异常的屏蔽:如果在执行finally语句时抛出异常,那么,catch语句的异常不能抛出原本的异常,会将finally代码块中得新异常信息抛出,原本的异常将不被打印出来:

四、自定义异常:

        在Java中除了核心类库给我们万宁的异常类之外,我们还可以定义自己所需要格式得自定义异常类在一个大型项目中,可以自定义新的异常类型,但是,保持一个合理的异常继承体系是非常重要的。一个常见的做法是自定义一个BaseException作为“根异常”,然后,派生出各种业务类型的异常。BaseException需要从一个适合的Exception派生,通常建议从RuntimeException派生:

五、使用Log4j:

1、使用Log4j的好处:

(1)可以设置输出级别,禁止某些级别输出。例如,只输出错误日志;

(2)可以被重定向到文件,这样可以在程序运行结束后查看日志;

(3)可以按包名控制日志级别,只输出某些包打的日志;

(4)可以规范项目开发;

2、使用Log4j输出的目的地:

(1)console:输出到屏幕;

(2)file:输出到文件;

(3)socket:通过网络输出到远程计算机;

(4)jdbc:输出到数据库

3、Log4j的日志级别:在Loggers(记录器)组件中,级别分6种:TRACE、DEBUG、INFO、WARN、ERROR和FATAL。

4、Log4j的应用:

(1)添加依赖:

     (1.1)把从Apache官网下载。下载并解压后,将下面1个jar包加入项目的classpath中commons-logging-1.2.jar

      (1.2)我们需要从Apache官网下载Log4j,解压后,把以下3个jar包放到classpath中:

(2)项目下创建lib文件夹 (与src同级),复制jar包到目录下,在将依赖导入项目依赖中

(3)创建log4j配置:在输出日志的过程中,通过Filter来过滤哪些log需要被输出,哪些log不需要被输出。例如,仅输出ERROR级别的日志。最后,通过Layout来格式化日志信息,例如,自动添加日期、时间、方法名称等信息。上述结构虽然复杂,但我们在实际使用的时候,并不需要关心Log4j的API,而是通过配置文件来配置它。虽然配置Log4j比较繁琐,但一旦配置完成,使用起来就非常方便。对上面的配置文件,凡是INFO级别的日志,会自动输出到屏幕,而ERROR级别的日志,不但会输出到屏幕,还会同时输出到文件。并且,一旦日志文件达到指定大小(1MB),Log4j就会自动切割新的日志文件,并最多保留10份。

(4)Log4j使用:第一步,通过LogFactory获取Log类的实例; 第二步,使用Log实例的方法打日志。

(1.1)在静态方法中引用Log,通常直接定义一个静态类型变量:

(1.2)在实例方法中引用Log,通常定义一个实例变量:

(1.3)在子类中使用父类实例化的log:


Exception异常处理:

在编程中,Exception(异常)是指程序运行过程中发生的意外情况或错误,这些情况会中断程序的正常执行流程。处理异常是编写健壮程序的重要部分。

异常的基本概念

  • 异常类型:不同的错误对应不同的异常类型,例如文件未找到(FileNotFoundError)、除以零(ZeroDivisionError)等
  • 异常处理:通过特定语法捕获并处理异常,防止程序崩溃
  • 异常传递:如果异常未被捕获,会向上传递,直到被捕获或导致程序终止

一、java异常:

     在计算机程序运行的过程中,总是会出现各种各样的错误。有一些错误是用户造成的,比如,希望用户输入一个int类型的年龄,但是用户的输入是abc

调用方如何获知调用失败的信息?有两种方法:

1、方法一:约定返回错误码。例如,处理一个文件,如果返回0,表示成功,返回其他整数,表示约定的错误码:

int code = processFile("C:\\test.txt");
if (code == 0) {
    // ok:
} else {
    // error:
    switch (code) {
    case 1:
        // file not found:
    case 2:
        // no read permission:
    default:
        // unknown error:
    }
}

2、方法二:在语言层面上提供一个异常处理机制。Java内置了一套异常处理机制,总是使用异常来表示错误。异常是一种class,因此它本身带有类型信息。异常可以在任何地方抛出,但只需要在上层捕获,这样就和方法调用分离了:

try {
    String s = processFile(“C:\\test.txt”);
    // ok:
} catch (FileNotFoundException e) {
    // file not found:
} catch (SecurityException e) {
    // no read permission:
} catch (IOException e) {
    // io error:
} catch (Exception e) {
    // other error:
}

3、异常的种类:首先分为error(严重错误不是人为的)和Exception(异常):

4、异常又分为运行时异常和编译异常:

(1)运行时异常:非必要处理异常
(1.1)java.lang.NullPointerException: 空指针异常

String str=null;

System.out.println(str.length());

(1.2) StringIndexOutOfBoundsException:下标越界异常

String str1="hello";

System.out.println(str1.charAt(5));

(1.3)java.lang.ArrayIndexOutOfBoundsException:数组下标越界

int[] arr=new int[0];
System.out.println(arr[0]);

(1.4)java.lang.ArithmeticException:算术异常(除0异常)

int Number =10/0;

System.out.println(Number);

(1.5)java.lang.NumberFormatException:格式异常

java.lang.NumberFormatException ;

int number=Integer.parseInt("f24");

System.out.println(number);

(1.6)ClassCastException:类型转换异常

Demo01 aa=(Demo01) (new Object());

System.out.println(aa);

 (2)编译时异常:IOException   UnsupportedEncodingException....除运行异常外都是编译异常

二、捕获异常:

1、捕获异常:必须处理异常(会报错)捕获异常使用try...catch语句,把可能发生异常的代码放到try {...}中,然后使用catch捕获对应的Exception及其子类:

public class Main {
    public static void main(String[] args) {
        byte[] bs = toGBK("中文");
        System.out.println(Arrays.toString(bs));
    }

    static byte[] toGBK(String s) {
        try {
            // 用指定编码转换String为byte[]:
            return s.getBytes("GBK");
        } catch (UnsupportedEncodingException e) {
            // 如果系统不支持GBK编码,会捕获到UnsupportedEncodingException:
            System.out.println(e); // 打印异常信息
            return s.getBytes(); // 尝试使用用默认编码
        }
    }
}

2、多个catch 语句:可以使用多个catch语句,每个catch分别捕获对应的Exception及其子类。JVM在捕获到异常后,会从上到下匹配catch语句,匹配到某个catch后,执行catch代码块,然后不再继续匹配。简单地说就是:多个catch语句只有一个能被执行。try块中可以放法多个异常代码,并且异常无关联,处理机制不同 ,try块出现异常,会跳转导对应的catch块,执行catch块中的内容,执行完成后,不会再返回到原出现异常的部分,进行下面的内容 ,异常后的代码不会执行。

public class Demo04 {
    public static void main(String[] args) {
        try {
            process1("123");
            process2(6);
            process3("hello你", "GBK");
        } catch (NumberFormatException ex) {
            ex.printStackTrace();
            System.out.println("方法1出错");
        } catch (IndexOutOfBoundsException ex) {
            ex.printStackTrace();
            System.out.println("方法2出错");
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
            System.out.println("方法3出错");
        }
//可使用短路或|连接
 try {
//            process1("123");
//            process2(2);
//            process3("hello你", "GBK");
//        } catch (NumberFormatException |IndexOutOfBoundsException|UnsupportedEncodingException ex) {
//            ex.printStackTrace();
//            System.out.println("异常了");
//
//        }


    }

    //NumberFormatException
    private static void process1(String s) {
        int number = Integer.parseInt(s);
        System.out.println(number);
    }

    //可能会有下表越界
    private static void process2(int index) {
        int[] arr = {1, 2, 3, 4, 5};
        System.out.println(arr[index]);
    }

    //次方阿飞可能会有UnsupportedEncodingException这类异常
    //属于编译时异常,必须要进行异常的处理和异常的捕获
    private static void process3(String str, String charSet) throws UnsupportedEncodingException {
        byte[] bytes = str.getBytes(charSet);
        System.out.println(Arrays.toString(bytes));
    }
}

3、finally代码块:无论是否有异常发生,如果我们都希望执行一些语句,例如清理工作,怎么写?可以把执行语句写若干遍:正常执行的放到try中,每个catch再写一遍。例如:

public static void main(String[] args) {
    try {
        process1();
        process2();
        process3();
        System.out.println("END");
    } catch (UnsupportedEncodingException e) {
        System.out.println("Bad encoding");
        System.out.println("END");
    } catch (IOException e) {
        System.out.println("IO error");
        System.out.println("END");
    }
}

上述代码无论是否发生异常,都会执行System.out.println("END");这条语句。那么如何消除这些重复的代码?Java的try ... catch机制还提供了finally语句,finally语句块保证有无错误都会执行。上述代码可以改写如下:

public static void main(String[] args) {
    try {
        process1();
        process2();
        process3();
    } catch (UnsupportedEncodingException e) {
        System.out.println("Bad encoding");
    } catch (IOException e) {
        System.out.println("IO error");
    } finally {
        System.out.println("END");
    }
}
(1)finally特点:
(1.1)finally语句不是必须的,可写可不写;
(1.2)finally总是最后执行。

如果没有发生异常,就正常执行try { ... }语句块,然后执行finally。如果发生了异常,就中断执行try { ... }语句块,然后跳转执行匹配的catch语句块,最后执行finally。可见,finally是用来保证一些代码必须执行的。

某些情况下,可以没有catch,只使用try ... finally结构。

void process(String file) throws IOException {
    try {
        ...
    } finally {
        System.out.println("END");
    }
}

4、注意事项:

(1)多个异常进行捕获需要注意顺序问题
(2)Catch捕获时自上而下进行异常的匹配,越是顶级的类,越要放到下面,写法遂循先子后父 /
(3) 再不然把多余的catch省略

三、抛出异常:

1、抛出异常的两种方式:

(1) throws声明异常: throws:声明异常,在方法上声明可能会出现的异常类型
    public static int divide1(int a,int b)throws ArithmeticException{
        return a/b;
    }
(2)throw  抛出异常: throw:扔出异常对象,放在方法体内,一般和if判断配合使用 
 //throw扔出编译异常外象,在方法上必须要声明此类的异常
    public static void process(String str) throws UnsupportedEncodingException, NullPointerException {
        if (str == null) {
            throw new NullPointerException("str为null了,请注意査");
        }
        if (!("6Bk".equalsIgnoreCase(str) || "uTF-8".equalsIgnoreCase(str))) {
            throw new UnsupportedEncodingException(str + "不符合编格式");
        };
        System.out.println(str);
    }

2、异常的传递:当某个方法抛出了异常时,如果当前方法没有捕获异常,异常就会被抛到上层调用方法,直到遇到某个try ... catch被捕获为止。

public class Main {
    public static void main(String[] args) {
        try {
            process1();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static void process1() {
        process2();
    }

    static void process2() {
        Integer.parseInt(null); // 会抛出NumberFormatException
    }
}

java.lang.NumberFormatException: null
    at java.base/java.lang.Integer.parseInt(Integer.java:614)
    at java.base/java.lang.Integer.parseInt(Integer.java:770)
    at Main.process2(Main.java:16)
    at Main.process1(Main.java:12)
    at Main.main(Main.java:5)

printStackTrace()对于调试错误非常有用,上述信息表示:NumberFormatException是在java.lang.Integer.parseInt方法中被抛出的,从下往上看,调用层次依次是:

  1. main()调用process1()
  2. process1()调用process2()
  3. process2()调用Integer.parseInt(String)
  4. Integer.parseInt(String)调用Integer.parseInt(String, int);

 3、异常的转换:在捕获异常的时候catch代码块里面又出现了一个新的异常,将新的异常信息传递给旧的异常信息。

public class Demo04 {
    public static void main(String[] args) {
        try {
            process1();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("end");
    }

    private static void process1() {
        try {
            process2();
        } catch (Exception e) {
           throw new IllegalArgumentException("参数不合法",e);
        }finally {
            System.out.println("end process1");
        }

    }

    private static void process2() {
        Integer.parseInt(null);
    }
}

4、异常的屏蔽:如果在执行finally语句时抛出异常,那么,catch语句的异常不能抛出原本的异常,会将finally代码块中得新异常信息抛出,原本的异常将不被打印出来:

public class Main {
    public static void main(String[] args) {
        try {
            Integer.parseInt("abc");
        } catch (Exception e) {
            System.out.println("catched");
            throw new RuntimeException(e);
        } finally {
            System.out.println("finally");
            throw new IllegalArgumentException();
        }
    }
}

       这说明finally抛出异常后,原来在catch中准备抛出的异常就“消失”了,因为只能抛出一个异常。没有被抛出的异常称为“被屏蔽”的异常(Suppressed Exception)。在极少数的情况下,我们需要获知所有的异常。如何保存所有的异常信息?方法是先用origin变量保存原始异常,然后调用Throwable.addSuppressed(),把原始异常添加进来,最后在finally抛出:

public class Main {
    public static void main(String[] args) throws Exception {
        Exception origin = null;
        try {
            System.out.println(Integer.parseInt("abc"));
        } catch (Exception e) {
            origin = e;
            throw e;
        } finally {
            Exception e = new IllegalArgumentException();
            if (origin != null) {
                e.addSuppressed(origin);
            }
            throw e;
        }
    }
}

四、自定义异常:

        在Java中除了核心类库给我们万宁的异常类之外,我们还可以定义自己所需要格式得自定义异常类在一个大型项目中,可以自定义新的异常类型,但是,保持一个合理的异常继承体系是非常重要的。一个常见的做法是自定义一个BaseException作为“根异常”,然后,派生出各种业务类型的异常。BaseException需要从一个适合的Exception派生,通常建议从RuntimeException派生:

 class BaseException extends RuntimeException{
    public BaseException() {
    }

    public BaseException(String message) {
        super(message);
    }

    public BaseException(String message, Throwable cause) {
        super(message, cause);
    }

    public BaseException(Throwable cause) {
        super(cause);
    }

}
class OrderTimeOutException extends BaseException {
    public OrderTimeOutException(String message) {
        super(message);
    }
}

public class Demo02{
    public static void main(String[] args) {
        checkOrderTime("0001",LocalDate.of(2025,07,12));
    }
    public static void checkOrderTime(String orderId,LocalDate orderDate){
//        if(LocalDate.now().minusDays(3).isBefore(orderDate)){
         if(LocalDate.now().getDayOfYear()-orderDate.getDayOfYear()<=3){
            System.out.println("未超时");
        }else {
            throw new OrderTimeOutException("订单超时:订单号"+orderId);
        }

    }
}

异常信息:

Exception in thread "main" com.yuan.myexception.OrderTimeOutException: 订单超时:订单号0001
    at com.yuan.myexception.Demo02.checkOrderTime(Order.java:16)
    at com.yuan.myexception.Demo02.main(Order.java:9)

五、使用Log4j:

Log4j 是一种非常流行的日志框架,Log4j 有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局)。这里可简单理解为日志类别日志要输出的地方日志以何种形式输出

综合使用这三个组件可以轻松地记录信息的类型和级别,并可以在运行时控制日志输出的样式和位置。Log4j 的架构大致如下:

1、使用Log4j的好处:

(1)可以设置输出级别,禁止某些级别输出。例如,只输出错误日志;
(2)可以被重定向到文件,这样可以在程序运行结束后查看日志;
(3)可以按包名控制日志级别,只输出某些包打的日志;
(4)可以规范项目开发;

2、使用Log4j输出的目的地:

(1)console:输出到屏幕;
(2)file:输出到文件;
(3)socket:通过网络输出到远程计算机;
(4)jdbc:输出到数据库

3、Log4j的日志级别:在Loggers(记录器)组件中,级别分6种:TRACEDEBUGINFOWARNERRORFATAL

级别是有顺序的:TRACE<DEBUG < INFO < WARN < ERROR < FATAL,分别用来指定这条日志信息的重要程度,明白这一点很重要,Log4j有一个规则:只输出级别不低于设定级别的日志信息

假设Loggers级别设定为INFO,则INFOWARNERRORFATAL级别的日志信息都会输出,而级别比INFO低的DEBUG则不会输出。最后,通过Layout来格式化日志信息,例如,自动添加日期、时间、方法名称等信息。

4、Log4j的应用:

(1)添加依赖:
     (1.1)把从Apache官网下载。下载并解压后,将下面1个jar包加入项目的classpathcommons-logging-1.2.jar
      (1.2)我们需要从Apache官网下载Log4j,解压后,把以下3个jar包放到classpath中:
  • log4j-api-2.x.jar

  • log4j-core-2.x.jar

  • log4j-jcl-2.x.jar
(2)项目下创建lib文件夹 (与src同级),复制jar包到目录下,在将依赖导入项目依赖中
(3)创建log4j配置:在输出日志的过程中,通过Filter来过滤哪些log需要被输出,哪些log不需要被输出。例如,仅输出ERROR级别的日志。最后,通过Layout来格式化日志信息,例如,自动添加日期、时间、方法名称等信息。上述结构虽然复杂,但我们在实际使用的时候,并不需要关心Log4j的API,而是通过配置文件来配置它。虽然配置Log4j比较繁琐,但一旦配置完成,使用起来就非常方便。对上面的配置文件,凡是INFO级别的日志,会自动输出到屏幕,而ERROR级别的日志,不但会输出到屏幕,还会同时输出到文件。并且,一旦日志文件达到指定大小(1MB),Log4j就会自动切割新的日志文件,并最多保留10份。
(4)Log4j使用:第一步,通过LogFactory获取Log类的实例; 第二步,使用Log实例的方法打日志。
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Main {
	public static void main(String[] args) {
		Log log = LogFactory.getLog(Main.class);
		log.trace("trace");//追踪级别
		log.debug("debug");//调试级别
		log.info("info");//普通信息
		log.warn("warn");//警告
		log.error("error");//错误级别
		log.fatal("fatal");//致命错误
	}

}
(1.1)在静态方法中引用Log,通常直接定义一个静态类型变量:
// 在静态方法中引用Log:
public class Main {
    static final Log log = LogFactory.getLog(Main.class);

    static void foo() {
        log.info("foo");
    }
}
(1.2)在实例方法中引用Log,通常定义一个实例变量:
// 在实例方法中引用Log:
public class Person {
    protected final Log log = LogFactory.getLog(getClass());

    void foo() {
        log.info("foo");
    }
}
(1.3)在子类中使用父类实例化的log:
// 在子类中使用父类实例化的log:
public class Student extends Person {
    void bar() {
        log.info("bar");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呼哧呼哧.

栓Q!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值