day07-异常&多线程

异常&多线程

第一章 异常

1、异常概述

异常: 不正常的情况

异常 :指的是程序在执行过程中,出现的不正常的情况,最终会导致JVM的非正常停止。

异常发生的原因有很多,通常包含以下几大类:

  • 用户输入了非法数据。
  • 要打开的文件不存在。
  • 网络通信时连接中断,或者JVM内存溢出。

这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。

**异常处理:**为了防止代码在运行期可能因为发生异常而导致的程序终止,我们需要将可能会出现问题的代码进行异常捕获并处理,使程序还可以继续运行下去。

在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象的过程。

Java处理异常的方式是中断处理(停止java虚拟机JVM)。

比如说我们常见的:空指针异常,索引越界异常等,都会导致JVM终止

2、异常的体系和分类

在这里插入图片描述

在Java中所有的问题都可以使用一个类来表示,这个类叫做Throwable。
异常的体系(重点)
-- java.lang.Throwable类:是所有异常和错误的父类
	Throwable 类是 Java 语言中所有错误或异常的超类。
	1.异常:小问题,就想平时生病感冒,发烧了,是可以治愈的
		在java中,异常我们是可以解决的,解决了异常之后,程序可以继续往后执行
		-- java.lang.Exception extends Throwable类:编译期异常,在写代码的时候,程序报的异常
		-- java.lang.RuntimeException extends Exception:运行期(时)异常,在运行代码的时候,程序报的异常.比较轻微的异常情况,而且通常情况,这种异常可以通过if语句来避免出现。 如:数组越界异常
	2.错误:严重问题,就想得了癌症,艾滋,是无法治愈的
		在java中,遇到了错误,必须的修改代码,不让错误出现
		-- java.lang.Error extends Throwable类 :错误
package com.itheima.demo01Exception;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 异常和错误的区别
 */
public class Demo01ExceptionAndError {
    public static void main(String[] args) {
        //-- java.lang.Exception extends Throwable类:编译期异常,在写代码的时候,程序报的异常
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = sdf.parse("2021-06-10");
            System.out.println(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        try {
            //-- java.lang.RuntimeException extends Exception:运行期(时)异常,在运行代码的时候,程序报的异常
            int[] arr = {10,20,30};
            System.out.println(arr[3]);  //ArrayIndexOutOfBoundsException:3
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("后续代码100行!");

    }
}

3、异常的产生过程解析(面试)

package com.itheima.demo01Exception;

/*
    异常的产生过程解析(面试)
    分析一下异常是如何产生的,发生异常之后JVM是如何处理异常的
 */
public class Demo02Exception {
    public static void main(String[] args) {
        int[] arr = {10,20,30};
        int e = getElement(arr, 3);
        System.out.println(e);
    }

    /*
        定义一个方法,方法的参数传递一个数组和数组的索引
        在方法中,获取数组指定索引处的元素返回
     */
    public static int getElement(int[] arr,int index){
        int ele = arr[index];
        return ele;
    }
}

在这里插入图片描述

4、throw关键字(重点)

 作用:
	让我们在[方法中]抛出指定的异常对象
	没有使用throw关键字,程序执行的过程中出现了异常,JVM会创建异常相关的对象,并抛出异常对象
格式:
	修饰符 返回值类型 方法名(参数列表){
		throw new xxxException("异常的错误信息");
		...
		throw new yyyException("异常的错误信息");
	}
注意:
	1.throw关键字必须写在[方法中]
	2.throw关键字后边创建的对象,必须是Exception或者RuntimeException或者他们的子类
		不能是和异常无关的对象(Person,Student==>错误)
	3.throw关键字抛出的是运行时()异常,我们无需处理异常,默认交给JVM处理(中断)
	  throw关键字抛出的是编译期异常,我们就必须的自己处理这个异常

package com.itheima.demo01Exception;

/*
    异常的产生过程解析(面试)
    分析一下异常是如何产生的,发生异常之后JVM是如何处理异常的
 */
public class Demo03Exception {
    public static void main(String[] args) {
        int[] arr = {10, 20, 30};
        //int[] arr = null;
        int e = getElement(arr, 3);
        System.out.println(e);
    }

    /*
        定义一个方法,方法的参数传递一个数组和数组的索引
        在方法中,获取数组指定索引处的元素返回
        在工作中,一般都会对方法传递来的参数,进行一些合法性的判断
            参数合法:使用参数参与计算
            参数不合法:使用抛出异常的方式,告之方法的调用者,传递的参数有问题
     */
    public static int getElement(int[] arr, int index) {
        /*
            对参数arr进行一个合法性的判断,判断arr是否为null
            数组的值是null,抛出空指针异常,告之方法的调用者“您传递的数组arr的值是null”
         */
        if (arr == null) {
            throw new NullPointerException("您传递的数组arr的值是null");
        }

        /*
            对参数index进行一个合法性的判断,判断index是否超出了数组索引的使用范围
            index超出了范围,抛出数组的索引越界异常,告之方法的调用者
            “您传递的数组索引index超出了索引的使用范围”
         */
        if (index < 0 || index > arr.length - 1) {
            throw new IndexOutOfBoundsException("您传递的数组索引" + index + "超出了索引的使用范围");
        }

        int ele = arr[index];
        return ele;
    }
}

5、throws关键字(重点)

异常处理的第一种方式
作用:
	throw关键字抛出的是编译期异常,我们就必须的处理这个异常
	可以使用throws关键字把异常对象抛出给方法的调用者处理,最终可以抛出给JVM处理(中断)
格式:
	修饰符 返回值类型 方法名(参数列表) throws xxxException,...yyyException{
		throw new xxxException("异常的错误信息");
		...
		throw new yyyException("异常的错误信息");
	}
 注意:
	1.在方法中抛出什么异常对象,就在方法上使用throws关键字声明抛出什么异常对象
		在方法中抛出多个异常对象,就需要在方法上声明多个异常对象
		在方法中抛出的多个异常对象,有子父类关系,在方法上声明父类异常对象即可
	2.调用了一个声明抛出异常对象的方法,必须的对这个异常对象进行处理
		可以使用throws关键字继续声明抛出异常对象给方法的调用者处理,最终会抛出给JVM处理
		可以使用try...catch关键字自己处理异常
弊端:
	最终会把异常对象抛出给JVM,JVM会中断我们当前正在执行的程序
	那么异常之后代码代码就不会执行了

package com.itheima.demo01Exception;

/*
    异常的产生过程解析(面试)
    分析一下异常是如何产生的,发生异常之后JVM是如何处理异常的
 */
public class Demo04Exception {
    public static void main(String[] args) throws Exception {
        int[] arr = {10, 20, 30};
        //int[] arr = null;
        int e = getElement(arr, 3);
        System.out.println(e);
    }

    /*
        定义一个方法,方法的参数传递一个数组和数组的索引
        在方法中,获取数组指定索引处的元素返回
        在工作中,一般都会对方法传递来的参数,进行一些合法性的判断
            参数合法:使用参数参与计算
            参数不合法:使用抛出异常的方式,告之方法的调用者,传递的参数有问题
     */
    public static int getElement(int[] arr, int index) throws Exception {
        /*
            对参数arr进行一个合法性的判断,判断arr是否为null
            数组的值是null,抛出空指针异常,告之方法的调用者“您传递的数组arr的值是null”
         */
        if (arr == null) {
            throw new Exception("您传递的数组arr的值是null");
        }

        /*
            对参数index进行一个合法性的判断,判断index是否超出了数组索引的使用范围
            index超出了范围,抛出数组的索引越界异常,告之方法的调用者
            “您传递的数组索引index超出了索引的使用范围”
         */
        if (index < 0 || index > arr.length - 1) {
            throw new Exception("您传递的数组索引" + index + "超出了索引的使用范围");
        }

        int ele = arr[index];
        return ele;
    }
}

6、throws抛出子父类异常的处理(重点)

在继承关系下,子类不能抛出比父类更多或更大的异常。

1.在方法中抛出什么异常对象,就在方法上使用throws关键字声明抛出什么异常对象

  在方法中抛出多个异常对象,就需要在方法上声明多个异常对象
  
  在方法中抛出的多个异常对象,有子父类关系,在方法上声明父类异常对象即可
package com.itheima.demo01Exception;

import java.io.FileNotFoundException;
import java.io.IOException;

/*
    1.在方法中抛出什么异常对象,就在方法上使用throws关键字声明抛出什么异常对象
 				在方法中抛出多个异常对象,就需要在方法上声明多个异常对象
 				在方法中抛出的多个异常对象,有子父类关系,在方法上声明父类异常对象即可

 		public static void main(String[] args) throws FileNotFoundException ,IOException
 		public static void main(String[] args) throws IOException
 		public static void main(String[] args) throws Exception
 */
public class Demo05Throws {
    public static void main(String[] args) throws Exception {
        readFile(null);

    }

    public static void readFile(String path) throws Exception{

        /*
            判断path是否为null,是null抛出IOException(读写异常)
            告之方法的调用者“您传递的文件的路径是null”
         */
        if(path==null){
            throw new IOException("您传递的文件的路径是null");
        }

        /*
            判断path是否为d:\\a.txt文件,不是,抛出FileNotFoundException(文件找不到异常)
            告之方法的调用者“您传递的文件路径不是d:\\a.txt”
         */
        if(!"d:\\a.txt".equals(path)){
            throw new FileNotFoundException("您传递的文件路径不是d:\\a.txt");
        }

        //文件路径没有问题,读取文件
        System.out.println("读取到了d:\\a.txt文件,文件中的内容是abc");
    }
}

7、try…catch关键字(重点)

Ctrl + alt + t 选择try catch

异常处理的第二种方式
作用
		1.throw关键字抛出的是编译期异常,我们就必须得处理这个异常
		2.调用了一个声明抛出编译期异常的方法,我们就必须得处理这个异常 就可以使用try catch关键字自己手动处理异常
格式:
	try{
		//可能产生异常的代码(也可以写没有异常的代码)
	}catch(定义一个异常相关的变量){//用来接收try中产生的异常对象
		//异常的处理逻辑:可以随意编写
	}
	...
	catch(定义一个异常相关的变量){//用来接收try中产生的异常对象
		//异常的处理逻辑:可以随意编写
	}
好处:
	使用try catch处理异常,可以继续执行try catch后边的代码
注意:
	1.try中产生了异常对象,那么就会执行catch中异常的处理逻辑,执行完毕会继续执行try catch之后的代码
	2.try中没有产生异常对象,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,会继续执行try catch之后的代码

package com.itheima.demo01Exception;

import java.io.FileNotFoundException;
import java.io.IOException;

/*
    异常处理的第二种方式
    作用
		1.throw关键字抛出的是编译期异常,我们就必须得处理这个异常
		2.调用了一个声明抛出编译期异常的方法,我们就必须得处理这个异常 就可以使用try catch关键字自己手动处理异常

 */
public class Demo06TtyCatch {
    public static void main(String[] args)  {
        try {
            //可能产生异常的代码,把异常代码抛出给catch中定义的变量
//            readFile(   null);
//            readFile("c:\\a.txt");
            readFile("d:\\a.txt");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("哈哈");
        }

        System.out.println("执行后续100行代码");
    }

    public static void readFile(String path) throws FileNotFoundException,IOException {

        /*
            判断path是否为null,是null抛出IOException(读写异常)
            告之方法的调用者“您传递的文件的路径是null”
         */
        if(path==null){
            throw new IOException("您传递的文件的路径是null");
        }

        /*
            判断path是否为d:\\a.txt文件,不是,抛出FileNotFoundException(文件找不到异常)
            告之方法的调用者“您传递的文件路径不是d:\\a.txt”
         */
        if(!"d:\\a.txt".equals(path)){
            throw new FileNotFoundException("您传递的文件路径不是d:\\a.txt");
        }

        //文件路径没有问题,读取文件
        System.out.println("读取到了d:\\a.txt文件,文件中的内容是abc");
    }
}

8、finally关键字(重点)

finally关键字里边定义的代码,无论程序是否有异常都会执行

Finally必须和try一起使用

package com.itheima.demo01Exception;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
     finally关键字里边定义的代码,无论程序是否有异常都会执行

        Finally必须和try一起使用
        
       try{
       		a
       }catch(异常类型 变量名){
            b
       }finally{
       	    c
       }
       
       try{
       
       }finally{
       	
       }
       
       try{
       
       }catch(异常类型 变量名){
       
       }catch(异常类型 变量名){
       
       }finally{
       	
       }
 */
public class Demo07Finally {
    public static void main(String[] args) throws ParseException {
        try {
            System.out.println("[1]可能会产生异常的代码");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = sdf.parse("2021-06-10");
            System.out.println(date);
        } catch (ParseException e) {
            System.out.println("[2]异常的处理逻辑");
            e.printStackTrace();
        } finally {
            System.out.println("[3]程序无论是否产生异常,都会执行的代码");
        }
        System.out.println("后续100行代码");

    }
}

9、异常处理的注意事项(了解)

在这里插入图片描述

package demo02Exception;

public class Demo01Exception {
    public static void main(String[] args) /*2、throws ArrayIndexOutOfBoundsException*/{
        /*try {
            int[] arr = {10,20,30};
            System.out.println(arr[3]); //1、ArrayIndexOutOfBoundsException: 3
        } catch (Exception e) {
            e.printStackTrace();
        }*/


        int[] arr = {10,20,30};
        System.out.println(arr[1]);

        System.out.println("后续代码");
    }
}

在这里插入图片描述

一句话:子类方法不能抛出比父类更大更多地方式。

package demo02Exception;

import java.io.IOException;

public class Demo02Fu {
    public void show01() throws IOException {

    }
}
package demo02Exception;

import java.io.IOException;

public class Demo03Zi extends  Demo02Fu {

    @Override
    public void show01() throws IOException {

    }
}

10、自定义异常(使用)

3.1 自定义异常概念
概念:
    java给我们提供异常类,不够我们使用,就需要自己定义一些异常相关的类
注意:
    1.自定义异常的类名,一般都是以Exception结尾,说明这个类就是一个异常相关的类(见名知意)
    2.自定义异常类
        a.可以继承Exception:自定义异常就是一个编译期异常
            使用:如果在方法中抛出了编译期异常,那么我们就必须处理这个异常,有两种处理方式
                1).使用throws关键字在方法上声明抛出这个异常对象,让方法的调用者处理,最终抛出给JVM(中断)
                2).使用try...catch自己捕获处理这个异常对象
       b.也可以继承RuntimeException:自定义异常就是一个运行期异常
            使用:如果在方法中抛出了运行期异常,我们无需处理,默认交给JVM处理(中断)

在这里插入图片描述

package com.itheima.demo03MyException;

//自定义一个异常类RegisterException,继承Exception,就是一个编译期异常
public class RegisterException extends Exception {

    public RegisterException() {
    }

    public RegisterException(String message) {
        super(message);
    }
}
package com.itheima.demo03MyException;

import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;

public class Demo01Test {

    public static void main(String[] args) throws RegisterException {
        //1、定义一个集合,存储用户已经注册过的用户名
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "jack", "rose", "tom", "jerry");

        //2、使用Scanner获取用户本次输入的用户名
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入您要注册的用户名:");
        String name = sc.nextLine();

        checkName(list, name);

    }

    /*
        3、定义一个方法,在方法中判断用户名是否已经被注册
     */
    private static void checkName(ArrayList<String> list, String name) throws RegisterException {
        for (String regName : list) {
            if(name.equals(regName)){
                throw new RegisterException("您输入的用户名" + name + "已经被注册了");
            }
        }

        list.add(name);
        System.out.println(list);

        System.out.println("恭喜您,注册成功!");
    }
}

第二章 多线程

我们在之前,学习的程序在没有跳转语句的前提下,都是由上至下依次执行,那现在想要设计一个程序,边打游戏边听歌,怎么设计?

要解决上述问题,咱们得使用多进程或者多线程来解决

1、并发并行

在这里插入图片描述

2、进程的概念

进程:进入到内存中的程序叫进程。
在这里插入图片描述

在这里插入图片描述

3、线程的概念

线程:是进程中的一个执行单元。负责当前进程中程序的执行,一个进程中至少有一个线程(单线程程序)。一个进程中是可以有多个线程的,这个应用程序也可以称这为多线程程序。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4、主线程

执行主方法的线程就叫主线程。

package com.itheima.demo05mainThread;

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println(name+"==>"+i);
        }
    }
}

package com.itheima.demo05mainThread;

public class Demo01MainThread {
    public static void main(String[] args) {
        Person p1 = new Person("tom");
        p1.run();

        Person p2 = new Person("jerry");
        p2.run();

    }
}

5、多线程程序创建的第一种方式_继承Thread类(重点)

package com.itheima.demo06Thread;

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("run==>"+i);
        }
    }
}
package com.itheima.demo06Thread;

/*
    多线程程序创建的第一种方式:继承Thread类(重点)
    java.lang.Thread类:是一个描述线程的类
    实现步骤:
        1、创建一个类 继承Thread类
        2、在Thread的子类中,重写Thread类的run方法,设置线程任务(开启新的线程要干什么 清理垃圾 查杀病毒)
        3、创建Thread类的子类对象
        4、调用start方法,开启一个新的线程,执行run方法

------------------------------------------------------------------
    void	start()  使该线程开始执行;java虚拟机调用这个线程的 run方法。
    1、调用start方法之后,结果是两个线程并发地运行:
        当前线程(main线程:执行main方法)和其他的线程(新的线程:执行run法)。
        两个线程一起抢夺cpu的执行权,谁抢到了谁执行,所以就有了随机性的打印结果(抢占式调度)
    2、多次启动一个线程是不合法的。特别是当线程已经结束执行后,不能再重新启动。
        一个线程对象,只能调用一次start方法。


 */
public class Demo01Thread {
    public static void main(String[] args) {

        MyThread myThread = new MyThread();
        //调用start方法,开启一个新的线程,执行run方法
        myThread.start();

        //主线程在开启新的线程后,会继续执行主方法中的代码
        for (int i = 0; i < 20; i++) {
            System.out.println("main==>"+i);
        }

    }
}

6、获取线程的名称

package com.itheima.demo07GetThreadName;

/*
    Thread类中的方法:获取线程名称
    1、可以使用Thread类中的方法getName
        String getName() 返回该线程的名称。

    2、可以先获取到当前正在执行的线程Thread对象
        static THread currentThread() 返回当前正在执行的线程对象的引用。
 */
public class MyThread extends Thread {

    @Override
    public void run() {
//        String name = getName();
//        System.out.println(name);

        //Thread t = Thread.currentThread();
        //String name = t.getName();
        //System.out.println(name);
      //链式编程
        System.out.println(Thread.currentThread().getName());
   }
}

package com.itheima.demo07GetThreadName;

public class Demo01GetThreadName {
    public static void main(String[] args) {

        MyThread mt = new MyThread();
        mt.start();

        new MyThread().start();
        new MyThread().start();
        new MyThread().start();

        //获取主线程的名称
        System.out.println(Thread.currentThread().getName());
    }
}

7、线程休眠

package com.itheima.demo08sleep;

/*
    Thread类中静态方法
        static void sleep(long mills)  1秒=1000毫秒
            在指定的毫秒内让当前正在执行的线程休眠(暂停执行)
            休眠结束,程序继续执行
 */
public class Demo01Sleep {
    public static void main(String[] args) {
        System.out.println("让当前线程(main线程)睡眠5秒钟");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("5秒钟已经到了,程序继续执行!");
    }
}

8、多线程程序创建的第二种方式:实现Runnable接口(重点)

package com.itheima.demo09Runnable;

public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"\t"+i);
        }
    }
}

package com.itheima.demo09Runnable;

/*
    实现步骤:
        1、创建Runnable接口的实现类,实现Runnable接口
        2、在实现类中重写Runnable接口的run方法,设置线程任务
        3、创建Runnable接口的实现类对象
        4、创建Thread类对象,构造方法的参数传递Runnable接口的实现类对象
        5、调用start方法开启一个新的线程,执行run方法
 */
public class Demo01Runnable {
    public static void main(String[] args) {
        RunnableImpl run = new RunnableImpl();

        Thread t = new Thread(run);
        t.start();

        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"==>"+i);
        }

    }
}

9、创建多线程程序的2种方式区别

在这里插入图片描述

package com.itheima.demo10ThreadAndRunnable;

public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(getName());
    }
}
package com.itheima.demo10ThreadAndRunnable;

public class MyRunnable1 implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"MyRunnable1");
    }
}
package com.itheima.demo10ThreadAndRunnable;

public class MyRunnable2 implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"MyRunnable2");
    }
}
package com.itheima.demo10ThreadAndRunnable;

public class Demo01Test {
    public static void main(String[] args) {

       /* MyThread mt = new MyThread();
        mt.start();*/

        MyRunnable1 mr1 = new MyRunnable1();

        MyRunnable2 mr2 = new MyRunnable2();

        Thread t = new Thread(mr2);
        t.start();

        //main线程名
        System.out.println(Thread.currentThread().getName());
    }
}

10、匿名内部类的方式实现多线程程序(重点)

package com.itheima.demo11Thread;

/*
    匿名内部类:简化代码
        把子类继承父类、重写父类的方法、创建子类对象 合成一步完成
        把实现接口、重写接口的方法、创建实现类对象 合成一步完成
    语法: new 爹
    	new Thread(){
    		public void run(){
    			....
    		}
    	}.tart();
    	
    	new Thread(new Runnable(){
    		public void run(){
    			....
    		}
    	}).start();
        
 */
public class Demo01Thread {
    public static void main(String[] args) {
        //父类:Thread类
        new Thread(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程执行了");
            }
        }.start();


        //接口:Runnable接口
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程执行了");
            }
        }).start();

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值