网站制作有哪些种类,怎样做网站性能优化,网站开发人员兼职,做3d同人的网站是什么概述 所有异常都是继承自java.lang.Throwable类#xff0c;Throwable有两个直接子类#xff0c;Error和Exception。
Error用来表示程序底层或硬件有关的错误#xff0c;这种错误和程序本身无关#xff0c;如常见的NoClassDefFoundError。这种异常和程序本身无关#xff0…概述 所有异常都是继承自java.lang.Throwable类Throwable有两个直接子类Error和Exception。
Error用来表示程序底层或硬件有关的错误这种错误和程序本身无关如常见的NoClassDefFoundError。这种异常和程序本身无关不需要检查属于非受检异常。
Exception表示程序异常可能是由于程序不严谨导致的如NPE空指针异常。Exception下面派生RuntimeException和其他异常其中RuntimeException表示运行时异常也属于非受检异常。在编译时可以不需要强制检查的异常不需要显式捕捉或抛出。
除Error和RuntimeException及派生类以外其他异常都属于受检异常如IOException、SQLException。在编译时强制进行检查的异常这种异常需要显式的通过try/catch来捕捉或通过throws抛出去否则程序无法通过编译。设计强制检查的异常受检异常主要原因是考虑到程序的正确性、稳定性和可靠性。
try…catch…finally语句块
初中级笔试题可能会出现的知识点。这里直接给出一些结论
受检异常需要使用try来包裹可能会抛出异常的代码块catch用于捕获异常并处理异常的代码块常见的处理策略包括打印错误日志、抛出自定义业务异常、释放资源、设置局部变量等受检异常还可以直接在方法签名上throws Exception抛给方法调用者来处理。业务开发中通常在Service层抛出自定义业务异常然后在Controller层统一捕获异常并返回errCode和errMsg不管有没有出现异常finally仍然会执行当try和catch中有return时finally仍然会执行finally常用于释放IO资源、分布式锁的持有、
常见异常
初中级Java开发工程师面试中经常会遇到的一个问题说说你工作中经常遇到的异常
面试官指的应该包括Exception和Error回答问题时不能只列举Exception。
简单列举Exception如下
NullPointerException简称NPE。多少人栽在NPE上多少资金损失是因为NPE。减少无法杜绝NPE的方法就是不停地空判断或使用Optional类。可喜的是升级到JDK 14以上版本发生NPE时JVM会打印具体哪个方法抛的空指针异常避免同一行代码多个函数调用时无法判断具体是哪个函数抛异常的困扰方便异常排查ConcurrentModificationException简称CME。当有多个迭代器同时遍历和修改Java集合如ArrayList或HashMap就有可能抛出CME异常。避免出现CME异常的措施如加锁使用CopyOnWriteArrayListConcurrentHashMap等集合。IndexOutOfBoundsException索引越界实现类有两个ArrayIndexOutOfBoundsException和StringIndexOutOfBoundsException。ClassCastException类型转换失败。ClassNotFoundException参考Java学习之NoClassDefFoundError、ClassNotFoundException、NoSuchMethodError
简单列举Error如下
OutOfMemoryErrorOOM报错信息为java.lang.OutOfMemoryError:Java heap spacess。遇到OOM时需要先分清楚是内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。StackOverflowError栈溢出。栈溢出的原因递归调用如求解斐波那契数列问题时大量循环或死循环全局变量过多数组、List、Map数据过大。NoClassDefFoundError找不到类定义NoSuchMethodError找不到方法NoSuchFieldError找不到字段上面这三种一般都是三方依赖冲突通过使用maven工具来排查如mvn dependency:tree tmp.txt或使用IDEA的Maven Helper插件
最佳实践
即所谓的Best Practice
在finally中清理资源坚决要杜绝捕获异常后不做任何处理即catch语句块为空捕获异常后的日志打印规范如记录错误类和方法记录详细的错误堆栈stacktrace方便排查问题使用Try-With-Resource语句实现AutoCloseable接口的资源优先捕获特定的异常其次再考虑其父类异常多使用自定义业务异常一个异常对应有一个errCode和一个可读性良好的errMsg
进阶
异常表
在JVM中异常处理不是由字节码指令早期使用jsr、ret指令来实现的而是异常表。
如果一个方法定义有try-catch或try-finally则会创建异常表保存异常处理信息
起始位置结束位置程序计数器记录的代码处理的偏移地址被捕获的异常类在常量池中的索引
Exception table
Exception table:from to target type0 12 15 Class java/lang/Exception根据不同的type对应到不同的target上。在操作系统里这个target也称为异常处理程序。就是特定问题出现时去异常表查询这个问题对应的是哪个处理程序然后去执行这个程序完成异常处理。
面试可能会遇到的问题finally为什么一定会执行 查看编译后的字节码可发现编译器把finally语句块里面的代码分别复制到try和catch语句块里面。
异常throw事件
jvmti中提供两个异常的事件一个是包含throw和catch一个是catch。选择功能多的那个方便一点。
void JNICALL Exception(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location, jobject exception, jmethodID catch_method, jlocation catch_location)通过方法签名可以知道异常的线程出异常的方法行号异常对象catch的方法和行号。这里由于是触发的throw事件所以如果只是new Exception的操作是不会触发事件的。有些代码通过创建Exception或Error来控制逻辑只要不是throwcatch的这种逻辑这里是检测不到的。如果异常只throw没有catch的话catch的字段就是空的。
拓展
UncaughtExceptionHandler
在虚拟机中当一个线程没有显式处理即try catch异常而抛出时会将该异常事件报告给该线程对象的java.lang.Thread.UncaughtExceptionHandler进行处理如果线程没有设置UncaughtExceptionHandler则默认会把异常栈信息输出到终端而使程序直接崩溃。所以如果想在线程意外崩溃时做一些处理就可以通过实现UncaughtExceptionHandler来满足需求。
public class Thread {/*** 当一个线程因未捕获的异常而即将终止时虚拟机将使用 Thread.getUncaughtExceptionHandler()* 获取已经设置的 UncaughtExceptionHandler 实例并通过调用其 uncaughtException(...) 方法而传递相关异常信息。* 如果一个线程没有明确设置其 UncaughtExceptionHandler则将其 ThreadGroup 对象作为其handler如果 ThreadGroup 对象对异常没有什么特殊的要求则 ThreadGroup 会将调用转发给默认的未捕获异常处理器即 Thread 类中定义的静态未捕获异常处理器对象。*/FunctionalInterfacepublic interface UncaughtExceptionHandler {/*** 未捕获异常崩溃时回调此方法*/void uncaughtException(Thread t, Throwable e);}/*** 静态方法用于设置一个默认的全局异常处理器*/public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {SecurityManager sm System.getSecurityManager();if (sm ! null) {sm.checkPermission(new RuntimePermission(setDefaultUncaughtExceptionHandler));}defaultUncaughtExceptionHandler eh;}/*** 针对某个Thread对象的方法用于对特定的线程进行未捕获的异常处理*/public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {checkAccess();uncaughtExceptionHandler eh;}/*** 当Thread崩溃时会调用该方法获取当前线程的 handler获取不到就会调用 grouphandler 类型。* group是Thread类的ThreadGroup类型属性在Thread构造中实例化*/public UncaughtExceptionHandler getUncaughtExceptionHandler() {if (isTerminated()) {// uncaughtExceptionHandler may be set to null after thread terminatesreturn null;} else {UncaughtExceptionHandler ueh uncaughtExceptionHandler;return (ueh ! null) ? ueh : getThreadGroup();}}/*** 线程全局默认handler*/public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {return defaultUncaughtExceptionHandler;}
}线程崩溃时异常抛出的顺序
先调用Thread.getUncaughtExceptionHandler()查看是否有自己对象特有的handler如果有就直接处理如果没有就调用ThreadGroupUncaughtExceptionHandler的默认实现类如果ThreadGroup没啥特殊处理就会继续调用Thread.getDefaultUncaughtExceptionHandler()获取handler进行处理如果默认handler也没有处理就直接执行正常的异常流程使程序崩溃。
ThreadGroup核心实现源码
// ThreadGroup在Thread对象构造方法中实例化
public class ThreadGroup implements Thread.UncaughtExceptionHandler {public void uncaughtException(Thread t, Throwable e) {// parent默认是nullif (parent ! null) {parent.uncaughtException(t, e);} else {// 一般走进来调用Thread.setDefaultUncaughtExceptionHandler(...)方法设置全局 handler进行处理Thread.UncaughtExceptionHandler ueh Thread.getDefaultUncaughtExceptionHandler();if (ueh ! null) {ueh.uncaughtException(t, e);} else if (!(e instanceof ThreadDeath)) {// 全局handler也不存在就输出异常栈System.err.print(Exception in thread \ t.getName() \ );e.printStackTrace(System.err);}}}
}Spring MVC异常处理机制
参考Spring MVC系列之九大核心组件中的HandlerExceptionResolver部分。
Spring MVC全局异常处理
每个Controller层里的方法都需要进行异常捕获及处理显然太繁琐且效率低。
自定义类并实现HandlerExceptionResolver接口并重写resolveException方法进行全局异常处理
Slf4j
Component
public class SimpleExceptionResolver implements HandlerExceptionResolver {Overridepublic ModelAndView resolveException(HttpServletRequest request, NonNull HttpServletResponse response, Object object, NonNull Exception e) {// 业务异常对前端可见否则统一归为系统异常MapString, Object map new HashMap();map.put(success, false);// 自定义业务异常可多次if判断对应多个异常类型当然也可使用switch语句if (e instanceof BusinessException) {map.put(errorMsg, e.getMessage());} else {map.put(errorMsg, system exception);}log.error(e.getMessage(), e);// 此处返回ModelandView对象如error.jsp页面也可考虑使用其他的模板引擎如FreeMarkerThymeleafreturn new ModelAndView(/error, map);}
}可以以不同的方式将异常结果返回给调用者前端或其他后端服务
返回ModelAndView返回页面的地址返回JSON返回HTTP错误码
当然也可以使用下面Spring Boot全局异常处理方案。
Spring Boot全局异常处理
直接给出配置类
Slf4j
// 复合注解 ControllerAdvice ResponseBody
RestControllerAdvice
public class GlobalExceptionHandler {// 别的方法都处理不了的异常ExceptionHandler(Exception.class)public ResponseObject otherExceptionHandler(HttpServletResponse response, Exception ex) {response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());log.error(ex.getMessage(), ex);return Response.error(服务器内部异常);}// 可捕获自定义异常、JDK或Spring异常支持数组形式捕获多个不同类型的异常但推荐一种异常对应一个方法ExceptionHandler({ForbiddenException.class}) // 自定义业务异常// ExceptionHandler({IllegalArgumentException.class}) // JDK异常// ExceptionHandler(HttpMessageNotReadableException.class) // Spring异常// 返回Response Status CodeResponseStatus(HttpStatus.FORBIDDEN)public ResponseObject forbidden(ForbiddenException e) {// 记录错误日志log.error(e.getMessage(), e);return Response.error(e.getMessage());}// 前端或接口攻击者使用非法的RequestBody请求接口解析异常字段并将错误日志降级ExceptionHandler(MethodArgumentNotValidException.class)public ResponseObject validationBodyException(MethodArgumentNotValidException exception) {BindingResult result exception.getBindingResult();StringBuilder errorMsg new StringBuilder();if (result.hasErrors()) {ListObjectError errors result.getAllErrors();errors.forEach(p - {FieldError fieldError (FieldError) p;errorMsg.append(fieldError.getDefaultMessage()).append(!);// 设置warn而不是error日志错误降级log.warn(Data check failure : object{ fieldError.getObjectName() },field{ fieldError.getField() },errorMessage{ fieldError.getDefaultMessage() });});}return Response.error(errorMsg.toString());}
}Response是自定义的数据统一返回格式
Data
NoArgsConstructor
public class ResponseT implements Serializable {private int code;private String msg;private T data;// 省略其他包装方法
}Dubbo处理异常
分布式调用链
参考
谈谈异常从JVM角度理解try…catch利用jvmti查看java异常UncaughtExceptionHandler相关问题解析