Exception、Thread(线程)

目录

1、Exception

(1)throw 关键字,自定义抛出异常的内容

(2)Objects中的requireNonNull()方法判断传递的参数是否为null

(3)处理异常的方式

a)第一种方式:通过throws抛出异常(异常后面的代码不会被执行)

b)第二种方式:通过 try...catch 捕获异常(异常后面的代码会继续执行)

(4)Throwable类中3个异常处理的方法

(5)finally代码块

(6)多个异常如果处理?

a)多个异常分别处理

b)多个异常一次捕获,多次处理

c)多个异常一次捕获,一次处理

(7)finally代码块中尽量避免出现return语句,因为会永远返回finally中的结果

(8)子父类异常

(9)自定义异常类

2、Thread(线程)

(1)创建多线程程序第一种方法:创建Thread类的子类

a)首先定义一个Thread类的子类,重写Thread类中的run方法,设置线程任务

b)创建Thread类的子类对象,用子类对象调用start()方法,开启新的线程

(2)创建多线程程序第二种方法:实现Runnable接口(常用方法)

a)创建一个Runnable接口的实现类,重写Runnable接口中的run方法,设置线程任务

b)创建Runnable接口的实现类对象,并创建Thread类对象,将实现类对象作为参数传递给Thread类对象

(3)使用匿名内部类的方式创建线程(常用简单方法)

(4)使用Lambda表达式的方式创建线程(最简单方法 JDK8特有)

(5)使用getName()方法返回线程的名称

a)首先定义一个Thread类的子类,重写Thread类中的run方法,设置线程任务

b)创建Thread类的子类对象,用子类对象调用start()方法,开启新的线程

(6)使用Thread类中的静态方法currentThread()方法返回正在执行的线程,再使用getName()方法返回线程的名称

a)首先定义一个Thread类的子类,重写Thread类中的run方法,设置线程任务

b)创建Thread类的子类对象,用子类对象调用start()方法,开启新的线程

(7)使用setName()方法设置线程的名称

a)首先定义一个Thread类的子类,重写Thread类中的run方法,设置线程任务

b)创建Thread类的子类对象,设置线程的名称,再用子类对象调用start()方法,开启新的线程

(8)使用带参数的构造方法设置线程的名称

a)首先定义一个Thread类的子类,重写Thread类中的run方法,设置线程任务

b)创建Thread类的子类对象,设置线程的名称,再用子类对象调用start()方法,开启新的线程

(9)使用sleep()方法使当前正在执行的线程暂停指定的毫秒数(模拟秒表)


1、Exception

(1)throw 关键字,自定义抛出异常的内容

package com.itheima.demo01Exception;
/*
throw关键字:作用:在指定的方法中抛出指定的异常
使用格式:throw new xxxException("异常产生的原因");
注意事项:
    1.throw关键字必须写在方法的内部
    2.throw关键字后边new的对象必须是Exception或者Exception的子类对象
    3.throw关键字抛出指定的异常对象,我们就必须处理这个异常对象
        throw关键字后边创建的是RuntimeException或者是RuntimeException的子类对象,我们可以不用处理,默认交给JVM处理(打印)
        throw关键字后边创建的是编译异常(写代码的时候报错),我们就必须处理这个异常,要么throws,要么try...catch
* */
public class Demo02Throw {
    public static void main(String[] args) {
//        int[] arr = null;
//        System.out.println(getElement(arr, 0));

        int[] arr1 = {1, 2, 3};
        System.out.println(getElement(arr1, 3));
    }

    /*
    定义一个方法,获取数组指定索引处的元素
    以后(工作中)我们必须首先对方法传递过来的参数进行合法性校验
    如果参数不合法,那么我们就必须使用抛出异常的方式,告知方法的调用者,传递的参数有问题
    * */
    public static int getElement(int[] arr, int index) {
        if (arr == null) {//对传递过来的数组进行合法性校验
            throw new NullPointerException("传递的数组的值是null");
        }
        if (index < 0 || index > arr.length - 1) {//对传递过来的索引进行合法性校验
            throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的使用范围");
        }
        return arr[index];
    }
}

(2)Objects中的requireNonNull()方法判断传递的参数是否为null

package com.itheima.demo01Exception;

import java.util.Objects;

public class Demo03Objects {
    public static void main(String[] args) {
        method(null);
    }
    public static void method(Object obj){
        //对传递过来的参数进行合法性判断,判断是否为null
        //自己写判断语句
        /*if (obj==null){
            throw new NullPointerException("传递的对象的值是null");
        }*/
        //使用Objects中的requireNonNull()方法判断
        //Objects.requireNonNull(obj);
        //使用Objects中的requireNonNull()方法判断并打印指定内容
        Objects.requireNonNull(obj,"传递的对象的值是null");
    }
}

(3)处理异常的方式

a)第一种方式:通过throws抛出异常(异常后面的代码不会被执行)

package com.itheima.demo01Exception;

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

public class Demo04Throws {
    public static void main(String[] args) throws IOException {
        readFile("c:\\a.txt");
    }
    //定义一个方法,对传递的文件路径进行合法性判断
    public static void readFile(String fileName) throws IOException {
        //如果路径不是"c:\\a.txt",那么我们就抛出文件找不到异常,告知方法的调用者
        if (!fileName.equals("c:\\a.txt")) {
            throw new FileNotFoundException("传递的文件路径不是c:\\a.txt");
        }
        //如果传递的路径不是.txt结尾,那么我们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对
        if (!fileName.endsWith(".txt")){
            throw new IOException("文件的后缀名不对!");
        }
        System.out.println("路径没有问题,读取文件!");
    }
}

b)第二种方式:通过 try...catch 捕获异常(异常后面的代码会继续执行)

package com.itheima.demo01Exception;

import java.io.IOException;

public class Demo05TryCatch {
    public static void main(String[] args) {
        try {
            //可能产生异常的代码
            //readFile("c:\\a.tx");
            readFile("c:\\a.txt");
        } catch (IOException e) {//try中抛出什么异常对象,catch中就定义什么异常变量,用来接收这个异常对象
            //异常的处理逻辑
            System.out.println("传递的文件的后缀名不是.txt");
        }
        System.out.println("后续代码...");

    }
    public static void readFile(String fileName) throws IOException {
        //如果传递的路径不是.txt结尾,那么我们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对
        if (!fileName.endsWith(".txt")){
            throw new IOException("文件的后缀名不对!");
        }
        System.out.println("路径没有问题,读取文件!");
    }
}

(4)Throwable类中3个异常处理的方法

package com.itheima.demo01Exception;

import java.io.IOException;

public class Demo05TryCatch {
    public static void main(String[] args) {
        try {
            //可能产生异常的代码
            readFile("c:\\a.tx");
        } catch (IOException e) {//try中抛出什么异常对象,catch中就定义什么异常变量,用来接收这个异常对象
            //异常的处理逻辑
            //System.out.println("传递的文件的后缀名不是.txt");

            //System.out.println(e.getMessage());//文件的后缀名不对!
            //System.out.println(e);//java.io.IOException: 文件的后缀名不对!
            //System.out.println(e.toString());//java.io.IOException: 文件的后缀名不对!
            e.printStackTrace();//打印的异常信息最全面
        }
        System.out.println("后续代码...");

    }
    public static void readFile(String fileName) throws IOException {
        //如果传递的路径不是.txt结尾,那么我们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对
        if (!fileName.endsWith(".txt")){
            throw new IOException("文件的后缀名不对!");
        }
        System.out.println("路径没有问题,读取文件!");
    }
}

(5)finally代码块

格式:
try{
    //可能产生异常的代码
}catch {
    //异常的处理逻辑
}finally {
    //无论是否出现异常,都会执行
}
package com.itheima.demo01Exception;

import java.io.IOException;

public class Demo06TryCatchFinally {
    public static void main(String[] args) {
        try {
            readFile("c:\\a.tx");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //无论是否出现异常,都会执行
            System.out.println("资源释放");
        }
    }
    public static void readFile(String fileName) throws IOException {
        //如果传递的路径不是.txt结尾,那么我们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对
        if (!fileName.endsWith(".txt")){
            throw new IOException("文件的后缀名不对!");
        }
        System.out.println("路径没有问题,读取文件!");
    }
}

(6)多个异常如果处理?

a)多个异常分别处理

package com.itheima.demo01Exception;

import java.util.List;

public class Demo07SomeException {
    public static void main(String[] args) {
        try {
            int[] arr = null;
            System.out.println(arr[0]);//NullPointerException
        } catch (NullPointerException e) {
            System.out.println(e);
        }

        try {
            List<Integer> list = List.of(1, 2, 3);
            System.out.println(list.get(3));//ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(e);
        }
        System.out.println("后续代码会继续执行...");
    }
}

打印结果:
java.lang.NullPointerException
java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
后续代码会继续执行...

b)多个异常一次捕获,多次处理

package com.itheima.demo01Exception;

import java.util.List;
//一个try多个catch注意事项:
//catch里边定义的异常变量如果有子父类关系,那么子类的异常变量必须写在上面,否则会报错
public class Demo07SomeException {
    public static void main(String[] args) {
        try {
            int[] arr = null;
            System.out.println(arr[0]);//NullPointerException
            List<Integer> list = List.of(1, 2, 3);
            System.out.println(list.get(3));//ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
        } catch (NullPointerException e) {
            System.out.println(e);
        }catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(e);
        }
        System.out.println("后续代码会继续执行...");
    }
}

打印结果:
java.lang.NullPointerException
后续代码会继续执行...

c)多个异常一次捕获,一次处理

package com.itheima.demo01Exception;

import java.util.List;

public class Demo07SomeException {
    public static void main(String[] args) {
        //多个异常,一次捕获,一次处理
        try {
            int[] arr = null;
            System.out.println(arr[0]);//java.lang.NullPointerException
            List<Integer> list = List.of(1, 2, 3);
            System.out.println(list.get(3));//java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
        } catch (Exception e) {
            System.out.println(e);
        }
        System.out.println("后续代码会继续执行...");
    }
}

打印结果:
java.lang.NullPointerException
后续代码会继续执行...

(7)finally代码块中尽量避免出现return语句,因为会永远返回finally中的结果

package com.itheima.demo01Exception;
//如果finally中有return语句,永远返回finally中的结果,应避免该情况
public class Demo08ReturnInFinally {
    public static void main(String[] args) {
        System.out.println(getA());
    }

    //定义一个方法,返回变量a的值
    public static int getA() {
        int a = 10;
        try {
            return a;
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            //一定会执行的代码
            a = 100;
            return a;
        }
    }
}

打印结果:
100

(8)子父类异常

package com.itheima.demo01Exception;

/*
子父类的异常:
    -如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常
    -父类方法没有抛出异常,子类重写父类该方法时也不可以抛出异常,此时子类产生该异常,只能捕获处理,不能声明抛出
注意:
    父类异常是什么样,子类异常就是什么样
* */
public class Fu {
    public void show01() throws NullPointerException, ClassCastException {}
    public void show02() throws IndexOutOfBoundsException {}
    public void show03() throws IndexOutOfBoundsException {}
    public void show04() {}
}
class Zi extends Fu {
    //子类重写父类方法时,抛出和父类相同的异常
    public void show01() throws NullPointerException, ClassCastException {}
    //子类重写父类方法时,抛出父类异常的子类
    public void show02() throws ArrayIndexOutOfBoundsException {}
    //子类重写父类方法时,不抛出异常
    public void show03() {}
    //父类方法没有抛出异常,子类重写父类该方法时也不可以抛出异常
//    public void show04() throws Exception{}//错误写法,不能抛出异常
    // 此时子类产生该异常,只能捕获处理,不能声明抛出
    public void show04() {
        try {
            throw new Exception("编译期异常");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

(9)自定义异常类

package com.itheima.demo02MyException;
/*
自定义异常类:
格式:
    public class XXXException extends Exception | RuntimeException{
        添加一个空参数的构造方法
        添加一个带异常信息的构造方法
    }
注意:
    1.自定义异常类一般都是以Exception结尾,说明该类是一个异常类
    2.自定义异常类,必须得继承Exception或者RuntimeException
        继承Exception:那么自定义的异常类就是一个编译器异常类,如果方法内部抛出了编译器异常,就必须处理这个异常,要么throws,要么try...catch
        继承RuntimeException:那么自定义的异常类就是一个运行期异常类,无需处理,交给JVM处理(中断处理)
* */
public class RegisterException extends Exception {
    //添加一个空参数的构造方法
    public RegisterException() {
        super();
    }

    //添加一个带异常信息的构造方法
    public RegisterException(String message) {
        super(message);
    }
}

2、Thread(线程)

(1)创建多线程程序第一种方法:创建Thread类的子类

a)首先定义一个Thread类的子类,重写Thread类中的run方法,设置线程任务

package com.itheima.demo03Thread;

//1.创建一个Thread类的子类
public class MyThread extends Thread {
    //2.在Thread类的子类中重写Thread类中的run方法,设置线程任务
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("run:" + i);
        }
    }
}

b)创建Thread类的子类对象,用子类对象调用start()方法,开启新的线程

package com.itheima.demo03Thread;

public class Demo01Thread {
    public static void main(String[] args) {
        //创建Thread类的子类对象
        MyThread thread = new MyThread();
        //调用Thread类中的start()方法,开启新的线程,执行run方法
        thread.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("main:"+i);
        }
    }
}

打印结果:
run:0
run:1
main:0
run:2
main:1
run:3
main:2
main:3
main:4
main:5
main:6
main:7
main:8
run:4
main:9
run:5
run:6
run:7
run:8
run:9

(2)创建多线程程序第二种方法:实现Runnable接口(常用方法)

实现Runnable接口创建多线程的好处:

①避免了单继承的局限性:

Ⅰ一个类只能继承一个类(一个人只能有一个爹),类继承了Thread类就不能继承其他的类

Ⅱ实现了Runnable接口,还可以继承其他的类,实现其他接口

②增强了程序的扩展性,降低了程序的耦合性

实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)

实现类中,重写了run方法:用来设置线程任务

创建Thread类对象,调用start方法:用来开启新线程

a)创建一个Runnable接口的实现类,重写Runnable接口中的run方法,设置线程任务

package com.itheima.demo03Thread;
//创建一个Runnable接口的实现类
public class RunnableImpl implements Runnable {
    //在实现类中重写Runnable接口的run方法,设置线程任务
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

b)创建Runnable接口的实现类对象,并创建Thread类对象,将实现类对象作为参数传递给Thread类对象

package com.itheima.demo03Thread;

public class Demo05Runnable {
    public static void main(String[] args) {
        //创建一个Runnable接口的实现类对象
        RunnableImpl runnable = new RunnableImpl();
        //创建Thread类对象,构造方法中传递Runnable接口的实现了对象
        Thread thread = new Thread(runnable);
        //调用Thread类中的start方法,开启新的线程执行run方法
        thread.start();

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

打印结果:
Thread-0:0
main:0
Thread-0:1
main:1
Thread-0:2
main:2
main:3
main:4
main:5
main:6
main:7
main:8
Thread-0:3
main:9
Thread-0:4
Thread-0:5
Thread-0:6
Thread-0:7
Thread-0:8
Thread-0:9

(3)使用匿名内部类的方式创建线程(常用简单方法)

匿名内部类作用:简化代码

①把子类继承父类、重写父类的方法、创建子类对象合成一步完成

②把实现类、实现类接口、重写接口中的方法、创建实现类对象合成一步完成

③匿名内部类的最终产物:子类/实现类对象,而这个类没有名字

package com.itheima.demo03Thread;

public class Demo06InnerClassThread {
    public static void main(String[] args) {
        //线程的父类是Thread
        new Thread(){
            //重写run方法,设置线程任务
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println(Thread.currentThread().getName()+"小强");
                }
            }
        }.start();
        //线程的接口Runnable
        Runnable runnable = new Runnable() {
            //重写run方法,设置线程任务
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println(Thread.currentThread().getName() + "旺财");
                }
            }
        };
        new Thread(runnable).start();

        //简化接口的方式
        new Thread(new Runnable() {
            //重写run方法,设置线程任务
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println(Thread.currentThread().getName() + "笨笨");
                }
            }
        }).start();
    }
}

打印结果:
Thread-1旺财
Thread-1旺财
Thread-0小强
Thread-1旺财
Thread-2笨笨
Thread-2笨笨
Thread-2笨笨
Thread-0小强
Thread-0小强

(4)使用Lambda表达式的方式创建线程(最简单方法 JDK8特有)

package com.itheima.demo03Lambda;
/*
    Lambda表达式的标准格式:
        由三部分组成:
            a.一些参数
            b.一个箭头
            c.一段代码
        格式:
            (参数列表) -> {一些重写方法的代码};
        解释说明格式:
            ():接口中抽象方法的参数列表,没有参数,就空着;有参数就写出参数,多个参数使用逗号分隔
            ->:传递的意思,把参数传递给方法体{}
            {}:重写接口的抽象方法的方法体
 */
public class Demo02Lambda {
    public static void main(String[] args) {
        //使用匿名内部类的方式,实现多线程
        new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+" 新线程创建了");
            }
        }).start();

        //使用Lambda表达式,实现多线程
        new Thread(()->{
                System.out.println(Thread.currentThread().getName()+" 新线程创建了");
            }
        ).start();

        //优化省略Lambda
        new Thread(()->System.out.println(Thread.currentThread().getName()+" 新线程创建了")).start();
    }
}

(5)使用getName()方法返回线程的名称

a)首先定义一个Thread类的子类,重写Thread类中的run方法,设置线程任务

package com.itheima.demo03Thread;
//定义一个Thread类的子类
public class GetThreadName extends Thread {
    //重写Thread类中的run方法,设置线程任务
    @Override
    public void run() {
        //获取线程名称
        String name = getName();
        System.out.println(name);
    }
}

b)创建Thread类的子类对象,用子类对象调用start()方法,开启新的线程

package com.itheima.demo03Thread;
//线程的名称:主线程:main
//            新线程:Thread-0,Thread-1,Thread-2...
public class Demo02GetThreadName {
    public static void main(String[] args) {
        //创建Thread类的子类对象
        GetThreadName name = new GetThreadName();
        //调用start方法,开启新线程,执行run方法
        name.start();

        new GetThreadName().start();
        new GetThreadName().start();
    }
}

打印结果:
Thread-1
Thread-0
Thread-2

(6)使用Thread类中的静态方法currentThread()方法返回正在执行的线程,再使用getName()方法返回线程的名称

a)首先定义一个Thread类的子类,重写Thread类中的run方法,设置线程任务

package com.itheima.demo03Thread;
//定义一个Thread类的子类
public class GetThreadName extends Thread {
    //重写Thread类中的run方法,设置线程任务
    @Override
    public void run() {
        //获取当前正在执行的线程
        Thread thread = Thread.currentThread();
        //System.out.println(thread);//Thread[Thread-0,5,main]
        //获取正在执行的线程的名称
        String name = thread.getName();
        System.out.println(name);//Thread-0

        //简洁方式(链式编程)
        System.out.println(Thread.currentThread().getName());
    }
}

b)创建Thread类的子类对象,用子类对象调用start()方法,开启新的线程

package com.itheima.demo03Thread;
//线程的名称:主线程:main
//            新线程:Thread-0,Thread-1,Thread-2...
public class Demo02GetThreadName {
    public static void main(String[] args) {
        //创建Thread类的子类对象
        GetThreadName name = new GetThreadName();
        //调用start方法,开启新线程,执行run方法
        name.start();

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

打印结果:
Thread-0
Thread-2
Thread-1
main

(7)使用setName()方法设置线程的名称

a)首先定义一个Thread类的子类,重写Thread类中的run方法,设置线程任务

package com.itheima.demo03Thread;

public class SetThreadName extends Thread {
    @Override
    public void run() {
        //获取线程的名称
        System.out.println(Thread.currentThread().getName());
    }
}

b)创建Thread类的子类对象,设置线程的名称,再用子类对象调用start()方法,开启新的线程

package com.itheima.demo03Thread;

public class Demo03SetThreadName {
    public static void main(String[] args) {
        //开启多线程
        SetThreadName setName = new SetThreadName();
        //给线程起一个名称
        setName.setName("小强");
        setName.start();
    }
}

打印结果:
小强

(8)使用带参数的构造方法设置线程的名称

a)首先定义一个Thread类的子类,重写Thread类中的run方法,设置线程任务

package com.itheima.demo03Thread;

public class SetThreadName extends Thread {
    //使用带参数的构造方法
    public SetThreadName(){}
    public SetThreadName(String name){
        super(name);//把线程名称传递给父类,让父类(Thread)给子线程起一个名字
    }

    @Override
    public void run() {
        //获取线程的名称
        System.out.println(Thread.currentThread().getName());
    }
}

b)创建Thread类的子类对象,设置线程的名称,再用子类对象调用start()方法,开启新的线程

package com.itheima.demo03Thread;

public class Demo03SetThreadName {
    public static void main(String[] args) {
        new SetThreadName("旺财").start();
    }
}

打印结果:
旺财

(9)使用sleep()方法使当前正在执行的线程暂停指定的毫秒数(模拟秒表)

package com.itheima.demo03Thread;

public class Demo04Sleep {
    public static void main(String[] args) {
        //模拟秒表
        for (int i = 1; i <= 60; i++) {
            System.out.println(i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

打印结果:
1
2
3
...

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值