1 异常概述
- 异常:程序执行过程中,产出的问题,因为异常的问题程序的正常的逻辑中断
- Java程序在执行过程中所发生的异常事件可分为两类:异常最顶层的类Throwable
-
- Error: Java虚拟机无法解决的严重问题。 如: JVM系统内部错误、 资源耗尽等严重情况。
-
-
- StackOverflowError:栈深度溢出异常,比如递归方法,没有退出条件
- -Xss128k
- java.lang.OutOfMemoryError:OOM内存溢出异常,栈,堆,方法区,程序计数器不会发生
- -Xms4g
- -Xmx4g
- -xx:MaxMetespaceSize=512M
-
-
- Exception: 其它因编程错误或偶然的外在因素导致的一般性问题, 可以使用针对性的代码进行处
-
-
- RuntimeException:运行期异常,编译是不需要处理
-
-
-
-
- ClassCastException
- ArrayIndexOutOfBoundsException
- ArithmeticException
- NullPointerException
-
-
-
-
- 非RuntimeException:编译期需要处理(try catche 或者throws)
-
-
-
-
- FileNotFoundException
- IOException
- SQLException
-
-
1.1 堆内存OOM
- xms10m:初始堆内存10m
- xmx20m:最大堆内存20m
测试代码
public class Test1 {
static class OOM{
// int i = 0;
}
/**
* xms:初始化堆内存
* xmx:最大堆内存
* 360146 10m
* 810326 20m
* 1215488 40m
* @param args
*/
public static void main(String[] args) {
System.out.println("前面代码");
List<OOM> list = new ArrayList<>();
int i=0;
try {
while (true) {
i++;
list.add(new OOM());
}
} catch (Throwable e) {
System.out.println("=================多少次后发生异常:"+i);
e.printStackTrace();
}
}
}
设置jvm参数
- xmx40m:最大堆内存大小40m
- xms10m:初始堆内存大小10m
执行结果
前面代码
=================多少次后发生异常:1215488
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:265)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
at java.util.ArrayList.add(ArrayList.java:462)
at a_basic.Test1.main(Test1.java:27)
1.2 方法区(元空间)OOM
public class MetaspaceDemo {
static class OOM{}
public static void main(String[] args) {
int i = 0;//模拟计数多少次以后发生异常
try {
while (true){
i++;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOM.class);
enhancer.setUseCache(false); //产生动态代理时,不使用缓存,不断的向方法区加载类
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o,args);
}
});
enhancer.create();
}
} catch (Throwable e) {
System.out.println("=================多少次后发生异常:"+i);
e.printStackTrace();
}
}
}
设置最大方法区(元空间大小)
-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
结果:
=================多少次后发生异常:540
org.springframework.cglib.core.CodeGenerationException: java.lang.OutOfMemoryError-->Metaspace
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:557)
1.2 StackOverflowError栈深度溢出异常
StackOverflowError:栈深度⼤于虚拟机所允许的深度
static void f1() {
int i = 1;
f1();
}
/**
* StackOverflowError:栈寻址深度溢出异常,递归没有退出条件
*/
@Test
public void f2() {
System.out.println("前面代码");
f1();
System.out.println("后续代码");
}
结果:
前面代码
java.lang.StackOverflowError
at a_basic.Test1.f1(Test1.java:38)
at a_basic.Test1.f1(Test1.java:38)
1.3 其他异常
拷贝junit的jar包到项目
#创建lib目录
#拷贝junit的jar文件到目录
配置使用junit依赖
public class Test1 {
/**
* 空指针异常
*/
@Test
public void f3() {
System.out.println("前面代码");
String s = null;
s.trim();
System.out.println("后续代码");
}
/**
* java.lang.ArithmeticException: / by zero:0作为除数异常
*/
@Test
public void f4() {
System.out.println("前面代码");
int i = 1/0;
System.out.println("后续代码");
}
}
2 异常处理
2.1 try catch finally
/**
* ClassCastException
* 类型转换异常
*/
static void fn1() {
Object o = "abc";
Integer i = (Integer) o;
int a = 1/0;
String s = null;
s.trim();
}
@Test
public void test6() {
System.out.println("步骤1");
try {
fn1(); //共享单车车胎坏了
} catch (ClassCastException e) {
System.out.println("ClassCastException");
//换了一个车
e.printStackTrace(); //test6在调用fn1的时候123行异常
} catch (NullPointerException e) {
//轱辘没了...
e.printStackTrace();
} catch (Exception e) { //兜底,捕获除了上面2个异常的所有异常
e.printStackTrace();
} finally {
System.out.println("还共享单车"); //释放资源,必须执行的代码
}
System.out.println("步骤3");
//运行期异常RuntimeException的子类,不需要处理,编译也不报错
}
e.printStackTrack()方法详解:
案例2:
public class Test2 {
public static void fn1() {
DataOutputStream out = null;
try {
out = new DataOutputStream(new FileOutputStream("d:\\a.txt"));
out.writeChar(97);
out.writeInt(1);
out.writeChar(98);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
fn1();
}
}
2.2 throws
throws:声明异常,当前方法不捕获(catch)异常,而是由调用这个方法的方法catch异常
注意RuntimeException不需要catch异常
案例3:
public static void fn1() throws IOException {
DataOutputStream out = new DataOutputStream(new FileOutputStream("d:\\c.txt"));
out.writeChar(97); //发生异常
out.writeInt(1);
out.writeChar(98);
out.close(); //有可能执行不到
}
public static void main(String[] args) {
//alt+enter:解决一切问题
try {
fn1();
} catch (IOException e) {
e.printStackTrace();
}
}
2.3 throw和自定义异常
throw:抛出一个异常,可以是一个自定义异常,语法
throw new MyException(); //抛出自定义异常
throw new RuntimeException(e);//抛出运行期异常
- 自定义异常
public class MyException extends Exception { public MyException() { } public MyException(String message) { super(message); } }
- Student
public class Student {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
if (id > 0) {
this.id = id;
} else {
// throw new RuntimeException("学员编号不能为负数"); //抛出运行期异常
//抛出自定义异常
throw new RuntimeException(new MyException("学员编号不能为负数")) ;
}
}
}
3.测试类
public class Test1 {
public static void main(String[] args) {
Student s = new Student();
s.setId(-1001);System.out.println(s.getId());
}}