异常处理和线程
异常和错误类型
java.lang.error——严重错误
- StackOverflowError栈溢出异常
public class FaFa extends Object {
char flower;
int number;
public FaFa(char flower, int number) {
plant(number);
this.flower = flower;
this.number = number;
}
public static int plant(int number) {
Feed(number);
System.out.println(number*=2);
return number*=2;
}
public static void Feed(int number){
plant(number);
}
}
public class Test {
public static void main(String[] args) throws java.lang.ArithmeticException {
FaFa f1 = new FaFa('花',2);
f1.Feed(f1.number);
//StackOverflowError栈溢出异常,由于feed和plant方法之间循环调用,不停开辟内存,导致栈内存空间不足。
}
}
- OutOfMemoryError内存溢出异常
public static void main(String[] args) throws java.lang.ArithmeticException {
List<FaFa> ll=new ArrayList<>();
for(;;){
ll.add(new FaFa());
}
//OutOfMemoryError内存溢出异常,由于不停创建新的实例,并保证实例一直有被引用无法释放,造成堆内存溢出异常。
}
java.lang.exception——异常情况(会导致JVM中断运行并提示错误)
public void printStackTrace();发生异常的位置、类型、原因;
public String getMessage();发生异常的原因
RuntimeException 的子类
ClassCastException类型转换异常
Object x = new Integer(0);
System.out.println((String)x);
//ClassCastException类型转换异常,编译时无法识别x的实际类型是integer;
ArithmeticException算术类异常
System.out.println(12/0);
//ArithmeticException算术类异常,发生于除以0等算术运算中的无效运算
NullPointerException空指针异常
int[] arr ={12,23,435,3125};
arr=null;
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
//NullPointerException空指针异常,arr数组中已经没有内容,无法遍历;
}
IndexOutOfBoundsException下标越界异常
- StringIndexOutOfBoundsException字符串下标越界异常
- ArrayIndexOutOfBoundsException数组下标越界异常
IllegalArgumentException非法参数异常
- NumberFormatException数字格式异常(extends IllegalArgumentException extends RuntimeException )
(试图将一个String转换为指定的数字类型,而该字符串不满足数字类型要求的格式)
System.out.println(Integer.parseInt("123"));
//正常
System.out.println(Integer.parseInt("wqe"));
//NumberFormatException数字格式异常,Integer.parseInt只能将数字格式的字符串转换成数字
Exception(如:IOException等)的其他子类
SQLException extends Exception
NoSuchMethodException(extends ReflectiveOperationException extends Exception )
方法调用时,路径下找不到该方法
ClassNotFoundException(extends ReflectiveOperationException extends Exception )
使用类名时,路径下找不到该类
FileNotFoundException(extends IOException extends Exception)
异常处理方式
自定义异常类
public class MyException extends RuntimeException {
public MyException() {
super();
}
public MyException(String s) {
super(s);
}
}
public static void main(String[] args) throws java.lang.Exception {
System.out.println("输入数字1-10");
Scanner s1=new Scanner(System.in);
if(s1.nextInt()<=10&& s1.nextInt()>=1){
System.out.println(s1.nextInt());
}else {
throw new MyException("输入数据超范围:"+s1.nextInt());
}
}
- 必须继承exception (编译时异常一般继承这个) 或runtimeException (运行时异常一般继承这个) 才能被throw
(只有exception类才能被throw) - 自定义异常类中可以封装一些提示信息
throw
- 方法内使用
- 一般与判断条件结合用
- 在throws后面可以写多个异常类,用逗号隔开
- A调用B,Bthrows了异常,A也必须throws同样的异常 或者 使用try catch处理异常==(runtime异常可以不处理不throws)==;
- 使用异常类时可以使用其getMessage()获取异常信息、printStackTrace()打印异常的跟踪栈信息并输出到控制台的方法
public static void main(String[] args) throws Exception {
System.out.println("输入数字1-10");
int a =new Scanner(System.in).nextInt();
if(a>10 || a<1){
Exception s=new MyException("输入数据越界,"+a);
System.out.println(s.getMessage());
System.out.println(s.getStackTrace());
throw s;
}else {
System.out.println(a*2);
}
结果:
//以下为getmessage
输入数据越界,12Exception in thread "main"
//以下为getStackTrace
[Ljava.lang.StackTraceElement;@28d93b30
//以下为throw s;
com.heima.study.MyException: 输入数据越界,12
at com.heima.study.TestThrow.main(TestThrow.java:9)
throw | throws | |
---|---|---|
位置 | 方法体内部 | 函数名后或参数列表后 |
含义 | 表示动作,此处抛出异常 | 表示倾向,可能不发生,即写了throws后面的方法中也可能没有异常、不抛出异常 |
用法 | 后面跟异常类的对象,只能有一个; throw之后除了finally语句块,不再执行任何语句 | 后面跟异常类名,可以多个(逗号间隔) |
try catch
格式
try{
可能会出现异常的代码
}catch(异常类型 e){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型 e2){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型 e3){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}finally{
}
优点
catch语句中可以不是抛出,而是解决方案(如打印某部分信息然后跳过此段),这样就不会导致程序中断;
不同使用方式
- 不处理异常
public class TestThrow {
public static void main(String[] args) throws Exception {
System.out.println(1);
Object x = new Integer(0);
System.out.println((String)x);
System.out.println(2);
}
}
-----------------------------------
运行结果:
1
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.heima.study.TestThrow.main(TestThrow.java:9)
- try catch处理异常
public class TestThrow {
public static void main(String[] args) throws Exception {
System.out.println(1);
try {
Object x = new Integer(0);
System.out.println((String)x);
} catch (ClassCastException e) {
System.out.println("存在异常"+e);
}
System.out.println(2);
}
}
---------------------------------------------
运行结果:
1
存在异常java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
2
- try catch抛出异常
public class TestThrow {
public static void main(String[] args) throws Exception {
System.out.println(1);
try {
Object x = new Integer(0);
System.out.println((String)x);
} catch (ClassCastException e) {
throw e;
}
System.out.println(2);
}
}
---------------------运行结果:
1
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.heima.study.TestThrow.main(TestThrow.java:9)
- try catch 抛出异常 finally
public static void main(String[] args) throws Exception {
System.out.println(1);
try {
Object x = new Integer(0);
System.out.println((String)x);
} catch (ClassCastException e) {
throw e;
} finally {
System.out.println(2);
}
System.out.println(3);
}
---------------------------------------------------
1
Exception in thread "main" 2
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.heima.study.TestThrow.main(TestThrow.java:9)
线程与进程
线程与进程
线程:进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程;
进程:程序执行的一次过程,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;
并发与并行
并发:同一时段执行(微观来看还是交替的,只是线程调度速度快(java是抢占式调度,根据优先级))
并行:同一时间执行(多核处理器可以同时分别处理多个线程)
创建线程
继承thread类
-
定义子类继承thread类,并重写run()方法(线程执行体),run的方法体就是线程需要完成的任务。
-
创建Thread子类的实例,调用start()方法启动线程;
start() start会开启一条新的线程,在新线程就绪后开始执行重写的run方法;但是start后面的方法不用等start执行,(start会与其交替执行) run() 就是个普通的方法,按代码顺序执行;不建议直接使用。
例:
public static void main(String[] args) {
System.out.println("11");
Test2 t =new Test2("zoya的线程");
t.start();
System.out.println("------------");
for (int i = 0; i < 10; i++) {
System.out.println("main线程!"+i);
}
System.out.println("------------");
t.run();
System.out.println("main线程结束");
}
运行结果如下:(start开辟的方法甚至也可以晚于main方法结束,此处只是偶然)
实现runnable接口
- 避免了单继承的限制(单继承导致一个类无法既继承父类又继承thread开辟新线程)
- 提高效率
- ==线程池(待学习)==只能放入runnable类线程,不能放入thread的子类。