Java基础(5)

Java异常处理

Java自定义异常

自定义异常的语法形式为:

<class><自定义异常名><extends><Exception>

在编码规范上,一般将自定义异常类的类名命名为 XXXException,其中 XXX 用来代表该异常的作用。

自定义异常类一般包含两个构造方法:一个是无参的默认构造方法,另一个构造方法以字符串的形式接收一个定制的异常消息,并将该消息传递给超类的构造方法。

例如,以下代码创建一个名称为 IntegerRangeException 的自定义异常类:

class IntegerRangeException extends Exception {
    public IntegerRangeException() {
        super();
    }
    public IntegerRangeException(String s) {
        super(s);
    }
}

使用自定义异常

throw new IntegerRangeException();

Java的异常跟踪栈

异常对象的 printStackTrace() 方法用于打印异常的跟踪栈信息,根据 printStackTrace() 方法的输出结果,开发者可以找到异常的源头,并跟踪到异常一路触发的过程

下面用于测试 printStackTrace 的例子程序

public class Test8 {
	class SelfException extends RuntimeException {
	    SelfException() {
	    }
	    SelfException(String msg) {
	        super(msg);
	    }
	}
    public static void firstMethod() {
        secondMethod();
    }
    public static void secondMethod() {
        thirdMethod();
    }
    public static void thirdMethod() {
        throw new Test8().new SelfException("自定义异常信息");
    }
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		firstMethod();
	}
}

运行上面程序,会看到如下所示的结果

Exception in thread "main" com.zengraoli.test.Test8$SelfException: 自定义异常信息
	at com.zengraoli.test.Test8.thirdMethod(Test8.java:20)
	at com.zengraoli.test.Test8.secondMethod(Test8.java:17)
	at com.zengraoli.test.Test8.firstMethod(Test8.java:14)
	at com.zengraoli.test.Test8.main(Test8.java:25)

上面运行结果的第 2 行到第 5 行之间的内容是异常跟踪栈信息,从打印的异常信息我们可以看出,异常从 thirdMethod 方法开始触发,传到 secondMethod 方法,再传到 firstMethod 方法,最后传到 main 方法,在 main 方法终止,这个过程就是 Java 的异常跟踪栈

Java.util.logging:JDK自带记录日志类

每个初学者都很熟悉在有问题的代码中使用 System.out.println 方法在控制台打印消息,来帮助观察程序运行的操作过程。如果你使用 System.out.println 方法,一旦发现问题的根源,就要将这些语句从代码中删去。如果接下来又出现了问题,就需要再插入几个调用 System.out.println 方法的语句,如此反复,增加了工作量。

日志用来记录程序的运行轨迹,方便查找关键信息,也方便快速定位解决问题。下面介绍 Java 自带的日志工具类 java.util.logging 的使用。

如果要生成简单的日志记录,可以使用全局日志记录器并调用其 info 方法,代码如下:

Logger.getGlobal().info("打印信息");

JDK Logging 把日志分为如下表 7 个级别,等级依次降低

级别SEVEREWARNINGINFOCONFIGFINEFINERFINEST
调用方法severe()warning()info()config()fine()finer()finest()
含义严重警告信息配置良好较好最好

Logger 的默认级别是 INFO,比 INFO 级别低的日志将不显示。Logger 的默认级别定义在 jre 安装目录的 lib 下面。

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO

所以在默认情况下,日志只显示前三个级别,对于所有的级别有下面几种记录方法:

logger.warning(message);
logger.fine(message);

同时,还可以使用 log 方法指定级别,例如:

logger.log(Level.FINE, message);

示例代码

import java.util.logging.Logger;

public class Test9 {

	private static Logger log = Logger.getLogger(Test9.class.toString());
	
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 级别依次升高,后面的日志级别会屏蔽之前的级别
        log.finest("finest");
        log.finer("finer");
        log.fine("fine");
        log.config("config");
        log.info("info");
        log.warning("warning");
        log.severe("server");
	}

}

输出结果为:

1月 14, 2021 4:04:25 下午 com.zengraoli.test.Test9 main
信息: info
1月 14, 2021 4:04:25 下午 com.zengraoli.test.Test9 main
警告: warning
1月 14, 2021 4:04:25 下午 com.zengraoli.test.Test9 main
严重: server

可以使用 setLevel 方法设置级别,例如logger.setLevel(Level.FINE);可以将 FINE 和更高级别的都记录下来。另外,还可以使用 Level.ALL 开启所有级别的记录,或者使用 Level.OFF 关闭所有级别的记录。

注意:如果将记录级别设计为 INFO 或者更低,则需要修改日志处理器的配置。默认的日志处理器不会处理低于 INFO 级别的信息。

Java 9增强的自动资源管理

Java9之前的trycatch代码都显得很臃肿,例如以下代码。

public static void main(String[] args) {
    FileInputStream fis = null;
    try {
        fis = new FileInputStream("a.txt");
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        // 关闭磁盘文件,回收资源
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Java7的优化

Java 7 以前,上面程序中的 finally 代码块是不得不写的“臃肿代码”,为了解决这种问题,Java 7 增加了一个新特性,该特性提供了另外一种管理资源的方式,这种方式能自动关闭文件,被称为自动资源管理(Automatic Resource Management)。该特性是在 try 语句上的扩展,主要释放不再需要的文件或其他资源。

自动资源管理替代了 finally 代码块,并优化了代码结构和提高程序可读性。语法如下:

try (声明或初始化资源语句) {
    // 可能会生成异常语句
} catch(Throwable e1){
    // 处理异常e1
} catch(Throwable e2){
    // 处理异常e1
} catch(Throwable eN){
    // 处理异常eN
}

当 try 代码块结束时,自动释放资源。不再需要显式的调用 close() 方法,该形式也称为“带资源的 try 语句”。

注意:

  • try 语句中声明的资源被隐式声明为 final,资源的作用局限于带资源的 try 语句。
  • 可以在一条 try 语句中声明或初始化多个资源,每个资源以;隔开即可。
  • 需要关闭的资源必须实现了 AutoCloseable 或 Closeable 接口。

Closeable 是 AutoCloseable 的子接口,Closeable 接口里的 close() 方法声明抛出了 IOException,因此它的实现类在实现 close() 方法时只能声明抛出 IOException 或其子类;AutoCloseable 接口里的 close() 方法声明抛出了 Exception,因此它的实现类在实现 close() 方法时可以声明抛出任何异常。

使用带Closeable接口的几个类,自动关闭资源的 try 语句相当于包含了隐式的 finally 块(这个 finally 块用于关闭资源),因此这个 try 语句可以既没有 catch 块,也没有 finally 块

public class AutoCloseTest {
    public static void main(String[] args) throws IOException {
        try (
                // 声明、初始化两个可关闭的资源
                // try语句会自动关闭这两个资源
                BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));
                PrintStream ps = new PrintStream(new FileOutputStream("a.txt"))) {
            // 使用两个资源
            System.out.println(br.readLine());
            ps.println("C语言中文网");
        }
    }
}

Java 7 几乎把所有的“资源类”(包括文件 IO 的各种类、JDBC 编程的 Connection 和 Statement 等接口)进行了改写,改写后的资源类都实现了 AutoCloseable 或 Closeable 接口。

Java9的优化

Java 9 再次增强了这种 try 语句。Java 9 不要求在 try 后的圆括号内声明并创建资源,只需要自动关闭的资源有 final 修饰或者是有效的 final (effectively final),Java 9 允许将资源变量放在 try 后的圆括号内。上面程序在 Java 9 中可改写为如下形式

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;

public class Test10 {
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		// 有final修饰的资源
		File file = new File("Hello1.txt");
        // 创建文件
        file.createNewFile();
        // creates a FileWriter Object
        FileWriter writer = new FileWriter(file);
        try(writer) {
			writer.write("This\n is\n an\n example\n");
	        writer.flush();
		}
        
		final BufferedReader br = new BufferedReader(new FileReader("Hello1.txt"));
		final PrintStream ps = new PrintStream(new FileOutputStream("a.txt"));
		// 只要将两个资源放在try后的圆括号内即可
		try(br; ps) {
			// 使用两个资源
			System.out.println(br.readLine());
			ps.println("C语言中文网");
		}
	}
}

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值