暑假充电计划开启中-------------------
———— 错误 ——————-
OutOfMemoryError
:内存耗尽
NoClassDefFoundError
:无法加载某个Class
StackOverflowError
:栈溢出
常见异常图表:
Exception
│
├─ RuntimeException
│ │
│ ├─ NullPointerException 对某个`null`的对象调用方法或字段
│ │
│ ├─ IndexOutOfBoundsException 数组索引越界
│ │
│ ├─ SecurityException
│ │
│ └─ IllegalArgumentException 参数检查不合法
│ │
│ └─ NumberFormatException 数值类型的格式错误
│
├─ IOException
│ │
│ ├─ UnsupportedCharsetException
│ │
│ ├─ FileNotFoundException 未找到文件
│ │
│ └─ SocketException 读取网络失败
│
├─ ParseException
│
├─ GeneralSecurityException
│
├─ SQLException
│
└─ TimeoutException
Java规定:
Exception
及其子类,但不包括RuntimeException
及其子类,这种类型的异常称为Checked Exception。Error
及其子类,RuntimeException
及其子类。使用 try ... catch ... 进行捕获
public class error {
public static void main(String[] args) {
byte[] bs = toGBK("中文");
System.out.println(Arrays.toString(bs));
}
static byte[] toGBK(String s) {
try {
return s.getBytes("GB");
} catch (UnsupportedEncodingException e) {
// 如果系统不支持GBK编码,会捕获到 UnsupportedEncodingException:
// 异常的寻找 查看 getBytes 源码, 看看会抛出什么异常, 就知道这里接受什么异常
// 实在不是很清楚异常是什么, 直接用 Exception 接受, 这也是最后办法。
System.out.println(e);
e.printStackTrace(); // 打印异常栈
return s.getBytes(); // 返回默认编码
}
}
}
在Java中,凡是可能抛出异常的语句,都可以用try ... catch
捕获。把可能发生异常的语句放在try { ... }
中,然后使用catch
捕获对应的Exception
及其子类。
可以使用多个catch
语句,每个catch
分别捕获对应的Exception
及其子类。捕获到异常后,会从上到下匹配catch
语句,匹配到某个catch
后,执行catch
代码块,然后不再继续匹配。
简单地说就是:多个catch
语句只有一个能被执行
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");
}
}
// UnsupportedEncodingException 是 IOException 异常的子类 , 所以需要放在前面
这里需要考虑一点, 如果异常不是子类的关系,那我们在编写多个catch 语句的时候, 如果下方代码是一样的, 就可以用 |
把这二个语句合并起来,就像这样 catch (IOException | NumberFormatException e)
,就可以少编写一些相同的代码, 避免造成冗余。
public static void main(String[] args) {
try {
System.out.println("捕获异常")
} catch (UnsupportedEncodingException e) {
System.out.println("Bad encoding");
} catch (IOException e) {
System.out.println("IO error");
}finally{
System.out.println("我一定会被执行的!")
}
}
注意几点:
finally
语句不是必须的,可写可不写;finally
总是最后执行。finally
总是确保一些语句一定会被执行throw Exception e
— (Exception 代表异常类型)
public class throwError {
public static void main(String[] args){
try {
fun1();
}catch (Exception e){
e.printStackTrace();
}
}
static void fun1(){
try {
fun2();
}catch (NullPointerException e){
throw new IllegalStateException(e);
}
}
static void fun2(){
throw new NullPointerException();
}
}
// 这样模拟了,异常是如何转换的, 我们在fun1中调入函数fun2抛出了一个异常, 然后又fun1, 去接受并且转换这个异常类型,
// 但这里要注意点, 在fun1 中, 如果不把这个原始异常向上抛出的话, 那么打印异常栈 就可能会出错, 就找不到错误的最终原因。
捕获到异常并再次抛出时,**一定要留住原始异常 ! **
异常栈 是最后打印的, 如果有finally 也是先打印 finally 之后,在打印异常栈。
如果产生了如何去捕获这个异常:
// 比如我们在这个反面代码中, 我们定义了 a b 空值。 这一定会报错。
public class throwError {
public static void main(String[] args) {
ss a = new ss();
System.out.println(a.b.toUpperCase());
}
}
class ss{
String a;
String b;
}
return Exception in thread "main" java.lang.NullPointerException
at random.throwError.main(throwError.java:6)
// 这个异常栈无法判断到底是谁产生了空值。 在JDK14中, 我们可以开启一个新的功能,就能捕获这种异常: 如下:
return Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because "a.b" is null
at random.throwError.main(throwError.java:6)
那再IDEA中,如何向JDK添加参数呢? 这个方法我也是询问别人才知道的, 哎。
第一步:
第二步:
参数: -XX:+ShowCodeDetailsInExceptionMessages
断言(Assertion)是一种调试程序的方式。在Java中,使用
assert
关键字来实现断言。
呃呃, 基本没啥用处, 懒得写笔记了, 最气人的还是这个功能现在默认都是关闭的, 代码运行到assert 就会直接忽略掉。
日志用来记录程序中出现的各种错误, 一般在容易出问题的代码下面加上日志语句,java中关于日志的类很多, 我总结一下。
好处:
"ERROR: " + var
;public class Hello {
public static void main(String[] args) {
Logger logger = Logger.getGlobal();
System.out.println("The main is starting!")
logger.info("start process...");
// logger.warning("warning ");
// logger.fine("ignored.");
// logger.severe("severe...");
}
}
return ---> The main is starting!
信息: start process
JDK的 Logging定义了7个日志级别,从严重到普通:
默认级别是INFO,因此,INFO级别以下的日志,不会被打印出来。使用日志级别的好处在于,调整级别,就可以屏蔽掉很多调试相关的日志输出, 但是这个Loggging是由局限性的,反正不是很好用, 这里介绍一下,作为一个了解就行了,使用其他方法更好!
Commons Logging是一个第三方日志库,它是由Apache创建的日志模块。
Commons Logging的特色是,它可以挂接不同的日志系统,并通过配置文件指定挂接的日志系统。默认情况下,Commons Loggin自动搜索并使用Log4j(Log4j是另一个流行的日志系统),如果没有找到Log4j,再使用JDK Logging.
这个库需要安装 !
Commons Logging定义了6个日志级别:
引用方法:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
// 实例方法引用
public class Person {
protected final Log log = LogFactory.getLog(getClass());
// 实例方法使用getClass() 继承的子类可以直接使用该log, 直接就能是用log的方式
void fun() {
log.info("The error tell me !");
}
}
// 静态方法引用
class Animal{
static final Log logs = LogFactory.getlog(Animal.Class);
// 静态方式只能使用 类 . Class 的方式去调用类名
static void fun(){
logs.info("The error not tell me!")
}
}
Commons Logging是使用最广泛的日志模块;
Commons Logging的API非常简单;
Commons Logging可以自动检测并使用其他日志模块。