JAVA异常

JAVA异常

Throwable

从继承关系可知:Throwable是异常体系的根,它继承自Object。
Throwable有两个体系:Error和Exception,Error表示严重的错误,程序对此一般无能为力
Error:
OutOfMemoryError:内存耗尽
NoClassDefFoundError:无法加载某个Class
StackOverflowError:栈溢出

Exception:
RuntimeException以及它的子类;
非RuntimeException(包括IOException、ReflectiveOperationException等等)

编译器对RuntimeException及其子类不做强制捕获要求,
不是指应用程序本身不应该捕获并处理RuntimeException。是否需要捕获,具体问题具体分析。

捕获异常

所有异常都可以调用printStackTrace()方法打印异常栈,这是一个简单有用的快速打印异常的方法。

抛出异常

为了能追踪到完整的异常栈,在构造异常的时候,把原始的Exception实例传进去,
新的Exception就可以持有原始Exception信息

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

    static void process1() {
        try {
            process2();
        } catch (NullPointerException e) {
            throw new IllegalArgumentException(e);  //这个地方一定要传进去 否则上层就找不到NullPointerException这个异常了
        }
    }

    static void process2() {
        throw new NullPointerException();
    }
}

finally

catch -> finally -> 抛出异常

异常屏蔽

catch->finally(如果这个地方抛出了异常,就直接结束不会再抛出catch的异常)->抛出异常

怎么才能在finally把所有异常都抛出呢
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;
}

通过Throwable.getSuppressed()可以获取所有的Suppressed Exception。
绝大多数情况下,在finally中不要抛出异常。因此,我们通常不需要关心Suppressed Exception

自定义异常

项目中抛出的一般都是自定义的异常
Exception
│
├─ RuntimeException
│  │
│  ├─ NullPointerException
│  │
│  ├─ IndexOutOfBoundsException
│  │
│  ├─ SecurityException
│  │
│  └─ IllegalArgumentException
│     │
│     └─ NumberFormatException
│
├─ IOException
│  │
│  ├─ UnsupportedCharsetException
│  │
│  ├─ FileNotFoundException
│  │
│  └─ SocketException
│
├─ ParseException
│
├─ GeneralSecurityException
│
├─ SQLException
│
└─ TimeoutException

BaseException需要从一个适合的Exception派生,通常建议从RuntimeException派生
public class BaseException extends RuntimeException {
}

public class UserNotFoundException extends BaseException {
}

public class LoginFailedException extends BaseException {
}

public class BaseException extends RuntimeException {
    public BaseException() {
        super();
    }

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

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

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

NullPointerException

尽量避免出现null,1.初始值的时候附上值 2. 逻辑判断的时候进行判断为null的处理
如果必须用null
使用Optional
例子:
      User user = new User();
      Address address = new Address();
//      House house = new House();
//      house.setName("hah");
//      address.setHouse(house);
      user.setAddress(address);
      Optional<User> userOptional = Optional.of(user);
      String name = userOptional.map(u->u.getAddress()).map(address1 -> address1.getHouse()).map(house1 -> house1.getName()).orElse("defff");
      System.out.println(name); //这时这个不会抛出异常 返回默认值  当有值得时候返回 非常优雅
      System.out.println(user.getAddress().getHouse().getName());  //这时这个会抛出异常

JAVA14 对NullPointerException进行了信息增强,能提示出哪个变量是null,但是默认是不开启的 如果要开启 需要配置JVM
XX:+ShowCodeDetailsInExceptionMessages 

使用断言 (Assertion) 是一种调试程序的方式 ,在java中使用assert关键字来实现断言


断言是一种调试方式,断言失败会抛出AssertionError,只能在开发和测试阶段启用断言
对可恢复的错误不能使用断言,而应该抛出异常
断言很少被使用,更好的方法是编写单元测试
开启断言的方法是 -enableassertions(可简写为-ea
public static void main(String[] args) {
        int x = -1;
        assert x > 0: "抛出异常";
        System.out.println(x);
    }

JDK Logging

Logger logger = Logger.getGlobal();
logger.info("start process...");
logger.warning("memory is running out...");
logger.fine("ignored.");
logger.severe("process will be terminated...");

缺点是:需要在JVM启动时传递参数-Djava.util.logging.config.file=<config-file-name>
所以更方便的是使用日志系统

Commons Logging

和Java标准库提供的日志不同,Commons Logging是一个第三方日志库,它是由Apache创建的日志模块,这是一个接口
首先会找Log4J,没有找到会使用JDK Logging

使用步骤:
1. 通过LogFactory获取Log类的实例
2. 使用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.info("start...");
        log.warn("end.");
    }
}
需要下载三方依赖然后打成jar包,执行测试命令
java -cp .;commons-logging-1.2.jar Main -cp是指定classpath

Commons Logging定义了6个日志级别
FATAl
ERROR
WARNING
INFO
DEBUG
TRACE

常用格式
// 在实例方法中引用Log:
public class Person {
    protected final Log log = LogFactory.getLog(getClass());

    void foo() {
        log.info("foo");
    }
}
log.error(String, Throwable)

Log4j

Common Logging 是日志接口
日志实现  是Log4j

Log4j 有几种记录日志的方式
console 输出到控制台
file 输出到文件里
socket 通过网络输出到远程计算机
jdbc 输出到数据库

Log4j配置文件名为log4j2.xml 依赖jar包为log4j-api-2.x.jar log4j-core-2.x.jar log4j-jcl-2.x.jar
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Properties>
        <!-- 定义日志格式 -->
		<Property name="log.pattern">%d{MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}%n%msg%n%n</Property>
        <!-- 定义文件名变量 -->
		<Property name="file.err.filename">log/err.log</Property>
		<Property name="file.err.pattern">log/err.%i.log.gz</Property>
	</Properties>
    <!-- 定义Appender,即目的地 -->
	<Appenders>
        <!-- 定义输出到屏幕 -->
		<Console name="console" target="SYSTEM_OUT">
            <!-- 日志格式引用上面定义的log.pattern -->
			<PatternLayout pattern="${log.pattern}" />
		</Console>
        <!-- 定义输出到文件,文件名引用上面定义的file.err.filename -->
		<RollingFile name="err" bufferedIO="true" fileName="${file.err.filename}" filePattern="${file.err.pattern}">
			<PatternLayout pattern="${log.pattern}" />
			<Policies>
                <!-- 根据文件大小自动切割日志 -->
				<SizeBasedTriggeringPolicy size="1 MB" />
			</Policies>
            <!-- 保留最近10份 -->
			<DefaultRolloverStrategy max="10" />
		</RollingFile>
	</Appenders>
	<Loggers>
		<Root level="info">
            <!-- 对info级别的日志,输出到console -->
			<AppenderRef ref="console" level="info" />
            <!-- 对error级别的日志,输出到err,即上面定义的RollingFile -->
			<AppenderRef ref="err" level="error" />
		</Root>
	</Loggers>
</Configuration>

SLF4J和Logback

SLF4j 相对Commons logging
commons logging
log.info("Set score " + score + " for Person " + p.getName() + " ok.");
SLF4j这么用
logger.info("Set score {} for Person {} ok.", score, p.getName());

Commons Logging	SLF4J
org.apache.commons.logging.Log	org.slf4j.Logger
org.apache.commons.logging.LogFactory	org.slf4j.LoggerFactory

不同之处就是Log变成了Logger,LogFactory变成了LoggerFactory。

jar包:slf4j-api-1.7.x.jar logback-classic-1.2.x.jar logback-core-1.2.x.jar

把logback.xml放到classpath下
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

	<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
		</encoder>
	</appender>

	<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<encoder>
			<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
			<charset>utf-8</charset>
		</encoder>
		<file>log/output.log</file>
		<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
			<fileNamePattern>log/output.log.%i</fileNamePattern>
		</rollingPolicy>
		<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
			<MaxFileSize>1MB</MaxFileSize>
		</triggeringPolicy>
	</appender>

	<root level="INFO">
		<appender-ref ref="CONSOLE" />
		<appender-ref ref="FILE" />
	</root>
</configuration>
        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-core -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

冰明子

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值