异常、线程

第一章 异常

1.1 概念及作用

1).“异常”:指程序在“运行时”JVM遇到了无法处理的数据,或者表达式,这种情况就叫:异常。(异常指的并不是语法错误

2).JVM遇到这种异常情况,通常是在控制台打印异常信息,然后结束掉程序(这是我们不希望看到的)

3).异常处理”的作用:就是允许我们的程序遇到这种异常情况后,可以跳过这段代码,继续执行后续的代码。

 前提:我们程序员在写代码的时候必须提前预知到这种异常情况,并预先做预处理

1.2 异常产生的过程解析

1).JVM执行到有异常的代码;

2).JVM要识别出这种异常;

3).JVM到类库中找到描述这个异常的“异常类”,并创建对象;

4).判断我们的代码中是否希望“捕获这种异常”:

是:去执行捕获异常的代码”(catch);

否:在控制台打印异常信息,并结束程序(这是我们不希望看到的)

1.3 Java异常体系结构及分类

1Throwable(顶层的异常父类)

|--Error(错误):不希望程序捕获并处理,因为无法处理

|--Exception(异常):希望程序捕获并处理的异常情况;

   |--RuntimeException(运行时异常):Java不要求强制捕获这种异常,这种异常通常是通过一些判断可以避免的异常。

   |--RuntimeException外的其它异常(编译期异常)Java要求必须强制捕获并处理,否则无法编译通过。这种异常通常无法通过判断避免。

2Throwable中常用方法:

1public void printStackTrace() :打印异常的详细信息(异常的跟踪栈信息并输出到控制台)。

包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace

2public String getMessage() :获取发生异常的原因

提示给用户的时候,就提示错误原因。

3public String toString() :获取异常的类型和异常描述信息(不用)

 

第二章 异常的处理

2.1 基本方式try...catch语句及执行流程

1).基本语法:

try{

//可能出现异常的代码

}catch(异常类名 变量名){

//如果try中出现了“异常类名”的异常,这里会被捕获,

           //会执行这里的代码

}

2).示例代码:

public static void main(String[] args) {
    updateStudent();
}
  public static void updateStudent(){
    Scanner sc = new Scanner(System.in);
    while(true) {
        System.out.println("请输入学号:");
        try {
            int stuNo = sc.nextInt();
            System.out.println("你输入的学号是:" + stuNo);
            break;//正常情况,结束循环
        } catch (InputMismatchException e) {
            System.out.println("你的输入有误!");
            sc = new Scanner(System.in);

Scannerbug,需写这步。否则,陷入死循环
        }
    }
    System.out.println("后续代码....");
}

3)执行流程

     出现异常时:会在异常那步直接跳到catch步骤中

 

2.2 常见的几种异常

1).空指针异常:NullPointerException(运行时异常)针对集合类

注意:当应用程序在需要对象的情况下尝试使用null时抛出 这些包括:

1)调用一个null对象的实例方法。

2)访问或修改null对象的字段。

3)以null的长度,好像是一个数组。

4)访问或修改null的插槽,就像它是一个阵列一样。

5)抛出null ,好像是一个Throwable价值。

 

1String s = null;

(注意:null的长度不存在,相同意思的String s=””的长度为0;其次,null无地址,String s=””有地址)

System.out.println(s.length());//编译通过,运行时抛出:NullPointerException

//最好要先做非空判断,然后再做其它处理

 

2String s = null;

   if(s != null){

 System.out.println(s.length());

   }

2) .数组下标越界异常:ArrayIndexOutOfBoundsException(运行时异常)针对数组

      注意:上述异常类继承自IndexOutOfBoundsException

int[] arr = {1,2,3};

System.out.println(arr[3]);//编译通过,运行时抛出:ArrayIndexOutOfBoundsException

//最好先判断索引是否有效

    int[] arr = {1,2,3};

if(3 < arr.length){

System.out.println(arr[3]);

}

3).数字转换异常:NumberFormatException(运行时异常)

String str = "24a";

int age = Integer.parseInt(str);

4).算术运算异常:ArithmeticException(运行时异常)

int a = 10;

int b = 0;

System.out.println(a / b);//编译通过,运行时抛出:ArithmeticException

5) .转换异常:ParseException(编译期异常)

--必须要捕获,否则编译错误

String str = "2018-08-08";

SimpleDateFormat  sdf = new SimpleDateFormat("yyyy-MM-dd");

try{

Date date = sdf.parse(str);

}catch(ParseException e){

.....

}

注意:还可以在main方法中向JDKthrows  ParseException()

2.3 try...catch...catch...语句及执行流程

 

 

注意:1)这种异常处理方式,要求多个catch中的异常不能相同

(2)catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面catch处理.

(3)找到一个异常后,不再执行try中的后续代码。

2.4 声明抛出异常throws

1声明异常:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲解该方式),那么必须通过throws进行声明,让调用者去处理。

2格式:修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2{ }

      注意:在throws后面可以写多个异常类

3)编码:

public static void main(String[] args)  {
    int[] arr = {432, 432, 43, 253};
    try {
        System.out.println("总和:" + sum(arr));
    } catch (NullPointerException e) {
        System.out.println("调用方法,接收到一个异常....");
    }
    System.out.println(sum(null));
}
public static int sum(int[] arr) throws NullPointerException,                                  ArrayIndexOutOfBoundsException,ArithmeticException {
    int sum = 0;
    for (int n : arr) {
        sum += n;
    }
    return sum;
}

注意:如果throws后面的是“编译期异常”,调用的代码必须要使用try...catch...或者继续抛出,否则编译错误。

如果throws后面的是“运行时异常”,调用处可以不处理,编译可以通过,但不建议。

自定义异常不写throws

2.5 抛出异常throw

public static void main(String[] args)  {
    int[] arr = {432, 432, 43, 253};
    try {
        System.out.println("总和:" + sum(null));
    } catch (NullPointerException e) {
        System.out.println("调用方法,接收到一个异常....");
        System.out.println("异常信息:" + e.getMessage());
    }
}
public static int sum(int[] arr)  {
    int sum = 0;
    if (arr == null) {
        throw new NullPointerException("哥们,你给我传了一个空指针,你太坏了....");
    }
    for (int n : arr) {
        sum += n;
    }
    return sum;
}

注意:如果throw抛出的是一个“运行时异常”,调用处可以不处理;

如果throw抛出了一个“编译期异常”,方法声明处必须显示的使用throws声明此异常,调用处也必须处理,否则编译错误;(即,编译期异常时,throwthrows都要抛出,也必须要处理异常。

2.6 Objects类的非空判断

1)代码:

class Student{

private String name;//要求姓名不能为:null

....

public Student(String name){

/*

if(name == null){

throw new NullPointerException("...");

}

if(...){

}*/

this.name = Objects.requireNonNull(name);//省去一个一个的非空判断

   }

}

main(){

Student stu = new Student("张三");

Student stu2 = new Student(null);

}

2throwsthrow的使用区别:

throws:表示“声明”此方法可能会产生某种异常,如果产生,请JVM将此异常对象抛给调用者。如果没有产生异常,则正常执行完毕。

public static void sum() throws NullPointerException{

...

}

throw:表示立即“抛出一个异常对象”

public static void sum(){

  if(...){

throw new NullPointerException("...");

   }

}

2.7 try...catch...finally语句

public String readFile(){

 try{

1.打开文件

2.读取文件内容;

4.return 文件内容;

}catch(Exception e){

//异常情况

return null;

}finally{

 //这里是:无论是否出现异常,都会被执行的

3.关闭文件

}

}

示例代码:

public static void main(String[] args) {
    String s = show();
    System.out.println("返回值:" + s);
}
public static String show(){
    try {
        System.out.println("1.打开文件");
        System.out.println("2.读取文件--出异常" + (10 / 0));
        return "呵呵呵";
    } catch (Exception e) {   
        System.out.println("异常了....");
        return null;
    }finally {
        System.out.println("3.关闭文件");
    }
}

 

第三章 自定义异常

3.1 概述

class Student{

private int age;

public void setAge(int age){

 //假如我们要求年龄必须在1550之间

if(age < 15 || age > 50){

throw new 自定义异常();

}

this.age = age;

}

}

为什么需要自定义异常:

1).类库中没有我们需要的异常;

3.2 自定义异常_自定义异常练习:

1).自定义异常的步骤:

A).自定义异常类--继承自Exception或者它的某个子类

   (RuntimeException/RuntimeException(建议))

B).建议:添加一个String参数的构造方法,用于设置“异常信息”

2).示例代码:

1).定义异常类:

public class AgeException extends Exception{
    public AgeException(String msg) {
        super(msg);
    }
}

(继承Exception默认继承编译器异常,extends  RunTimeException 继承运行期异常 )

2).使用异常类:

public class Student {
    private int age;

    public void setAge(int age) throws AgeException {
        if (age < 15 || age > 50) {
            throw new AgeException("年龄错误,必须在1550岁之间!");
        }
        this.age = age;
    }
}

3).测试代码:

public class Demo {
    public static void main(String[] args) {
        Student stu = new Student();

        try {
            stu.setAge(100);
        } catch (AgeException e) {
            System.out.println("异常信息:" + e.getMessage());
        }

    }
}

------------------------------------------------------------

第四章 多线程

4.1 进程与线程

1)“进程”:“进程”是操作系统的概念,一个独立运行的程序,就是一个“进程”。

2).“线程”:“线程”是由“进程创建”的,一个进程可以创建任意多的线程,每个线程都包含一些代码。线程中的代码会同主进程或者其他线程“同时运行”。

3).“多进程”:在某个时间段内,同时运行多个程序;

4).“多线程”:一个程序可以同时启动多个线程,也就意味着可以使多段代码“同时运行”,可以提高程序的运行效率。

我们之前写的程序都是:单线程程序--后面的代码总是等前面的代码执行完毕才能执行。

要使我们的程序可以“同时做多件事”,就需要制作多线程程序。

4.2 并发与并行:

1).并行:多个线程同时开始运行

2).并发:多个线程同时访问同一资源(CPU)。(指两个或多个事件在同一个时间段内发生。)

4.3 创建线程类_继承Thread及匿名对象的方式:

1).制作多线程程序,必须在设计阶段就要确定下来:哪些代码需要以独立的线程运行,从而来 制作线程类。

2).步骤

(1).定义线程类,继承自Thread

(2).重写run()方法;

 (3).启动线程:

  (3.1).创建一个线程对象;

  (3.2).调用对象的start()方法启动线程;

3).示例代码:

1).定义线程:

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("从网络接收外部数据....");

           }
         }
    }

2).启动线程:

public static void main(String[] args) {
     //先启动线程
     MyThread t = new MyThread();
     t.start();//启动线程,后,主方法继续向下运行

      for (int i = 0; i < 1000; i++) {
        System.out.println("从控制台接收数据.....");
      }
}

 

4.4 创建线程类_关于线程的几个说明:

1).匿名内部类的方式实现线程:

new Thread(){

public void run(){

for (int i = 0; i < 1000; i++) {
       System.out.println("从控制台接收数据.....");

}

}

   }.start();

2).重写的是run().但启动线程调用的是:start()

3).对于一个“线程对象”,只能调用一次start(),不能多次调用start()

MyThrad t = new MyThread();

t.start();

...

t.start();//编译通过,运行时异常

posted on 2018-10-14 13:37  水漾月  阅读(91)  评论(0编辑  收藏  举报

导航