A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 芷弦 中级黑马   /  2018-11-22 12:21  /  779 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文


## 异常概述
        * 概述:在代码的运行期间,由于代码的使用或者编写上的问题,出现了不正常的运行情况。
        * 在Java中异常也是以对象的形式出现。
        * 体系结构:
                * Throwable
                        * Error : 不应该处理的问题,比如说电脑主板坏了,通过系统优化是解决不了的
                        * Exception : 可以处理的问题,比如电脑中病毒,系统坏了,通过重装系统或者杀毒,就可以解决
## 异常分类(****)
        * 由于Error是不应该处理的问题,所以我们重点只研究:Exception
        * Exception
                * 编译期异常:
                        * 在编译期需要提前对异常进行【预处理】的异常,如果不处理则会编译失败。
                        * 如果是Exception除了RuntimeException之外的子类,则是编译期异常
                        * 举例:
                                1. ParseException
                                2. IOException
                * 运行时异常
                        * 编译期可以处理也可以不处理。
                        * 如果是RuntimeException及其子类则是运行时异常。
                        * 举例:
                                1. NullPointerException
                                2. ArithmeticException
                                3. ArrayIndexOutOfBoundsException
                * 比较两种异常区别:
                        * 本质上区别只有一点:编译期是否需要预处理。
                        * 编译期异常相较于运行时异常的区别只是编译期是否需要预处理,那么是否真正产生异常对象,那么还是看代码是否存在问题。
                                * 假设签订劳动合同:如果迟到就罚款100块。
                                        * 不是签订完合同就罚款,为了防止迟到,如果迟到了有方案去处理
                                        * 不是给出了预处理方案就已经出现了异常,代码有问题才出现,在出现问题后我们能有处理方案
## 异常的产生
        * 异常对象产生分析:
        1. 如果代码出现了问题JVM帮我们创建了一个索引越界的异常对象(我们也可以主动产生异常)
        2. 整个异常对象,包含了异常的信息:异常产生的位置,异常产生的原因....
        3. 如果没有给出特定的处理,默认异常对象会抛给方法调用者
        4. 如果最终抛给了JVM。则JVM会给出默认的处理

    * JVM默认处理:
        1. 中断程序的执行
        2. 在控制台打印异常信息
            异常信息:异常的类别,异常的原因,异常的位置
## 异常的处理(*****)
        1. 抛出
                1. 抛出异常(默认的处理)
            格式:throws 异常的类型
            位置:方法的参数列表后,在大括号之前
            作用:产生的异常对象会被抛出方法的调用者

                        对于编译期异常来说,显式声明抛出编译异常则相当于给出了异常处理方案,则可以编译通过
                        对于运行时异常来说,默认就是抛出异常,所以声明抛出与否没有区别。
        2. 捕获异常
         格式:
            try {
                // 有可能产生异常的代码
            } catch (异常类型 变量) {
                // 如果捕获到异常后的处理方案
            }

         注意:
                        1. catch中的代码只有当产生了对应的异常对象才会被执行
                        2. 如果异常对象和catch的类型不匹配,则这个异常对象不能被此catch处理
        3. 多异常的捕获处理
                方案:
                1. 每个有可能产生异常的代码都单独的try catch
                2. 一个try 多个catch

        注意:
            1. 如果有可能产生的异常未知,可以捕获一个父类型异常,此父类型异常和其任意的子类型异常都能被捕获
            2. 如果捕获多个异常有子父类关系,则父类catch必须在子类的后面
        4. finally
                * 在try catch后,还可以有一个finally的部分,这部分的代码在任意的情况下都会被执行
        作用:可以把一些代码的收尾工作,写在此位置,无论异常是否产生是否被处理,finally的部分都会被执行
## Throwable常用功能
    1. public String getMessage()  :  返回异常产生的原因
        2. public void printStackTrace() :将异常的类型原因和位置打印在控制台
        3. public String toString()  :返回异常的类型和原因
## 自定义异常(***)
        自定义异常:当别人使用我们编写的代码,如果别人的使用有问题,影响了代码的执行,则我们可以抛出一个异常对象,给方法的调用者,让其明确异常的信息
        1. 定义异常类
                1. 定义一个见名知意的类,继承异常父类
                        * 如果想定义的是编译期异常继承Exception
                        * 如果想定义的是运行时异常继承RuntimeException
                2. 编写两个构造方法:一个无参构造,一个带一个字符串参数的构造(需要调用父类指定构造)
        2. 使用
                在需要产生异常的位置:
            throw new 异常对象(异常的原因);

                注意:
                        如果产生的异常是编译期异常,需要在方法的声明上用throws关键字抛出异常
               
                throw  : "throw new 异常对象" 用于【产生异常】对象的,如果方法的调用者使用代码有误,则这个产生的异常会抛出方法的调用者
                throws : "throws 异常类型"  用于【处理异常】的,定义在方法声明上,将指定的异常抛给方法的调用者
               

## 多线程概述
        1. 进程和线程
                * 进程:正在运行中的应用程序
                * 线程:进程中的执行单元
                * 注意:
                        * 一个进程中至少要有一个线程
        2. 并发和并行
                * 并发:交替执行,其实CPU会在多个不同的线程间进行高速的切换,在某一个时刻其实只有一个线程被执行
                * 并行:同时执行,需要多核CPU才可以实现。
## 多线程的实现(*****)
        * JVM为了调用main方法,帮我们默认的开启了一个main线程,然后去调用main方法。
    * 线程的实现方式1:
            1. 定义类继承Thread
            2. 重写run方法
            3. 创建子类的实例
            4. 调用start方法启动线程(调用run方法不能开启新线程)

    * Thread常用功能:
        1. public String getName() 获取当前线程的名称
        2. public void setName(String name) 设置当前线程的名称
        3. public static void sleep(long mls) 让当前正在执行此代码的线程睡指定毫秒值
        4. public static Thread currentThread() 获取正在执行此代码的线程

## 线程开启的方式
        * 方式一 (继承Thread)
        1. 定义类继承Thread
        2. 重写run方法
        3. 创建Thread的子类对象
        4. 调用start方法开启线程

        * 线程开启的方式2 (实现Runnable接口)
        1. 定义类实现Runnable接口
        2. 重写run方法
        3. 创建Runnable实现类对象
        4. 创建Thread对象,将Runnable实现类对象传入Thread构造
        5. Thread对象调用start方法开启线程


        * Thread常用功能:
            String getName() 获取线程的名称
            void setName(String name) 设置线程的名称
            static void sleep(long millis) 让执行该代码的线程睡眠指定毫秒值
            static Thread currentThread() 获取正在执行此代码的线程

## 线程安全问题
        * 出现的原因:多线程操作共享数据

    * 解决线程安全问题的三种方案:
        1. 同步代码块:
            synchronized(锁对象) {
                // 有可能出现线程安全问题的代码
            }

        2. 同步方法:
            把有线程安全问题的代码提取成一个方法,在修饰符上加一个synchronized
            非静态同步方法的锁对象默认是:this
            静态同步方法的锁对象默认是:当前类.class

        3. Lock锁
            Lock lock = new ReentrantLock();

            在需要同步的代码前调用lock()获取锁
            在需要同步的代码后调用unlock()释放锁

## 线程的状态
        * NEW 【新建状态】:线程对象已经创建,但是没有调用start方法

        * RUNNABLE 【可运行状态】: 当调用了start方法并且没有陷入睡眠和等待

        * BLOCKED 【阻塞状态】:当同步代码中已经有线程在执行,其他的线程处于阻塞状态。

        * TIMED_WAITING 【计时等待】:
                1. 当调用了Thread.sleep()方法陷入睡眠,没有醒来,此时线程处于等待状态  【不会释放锁对象】
                2. void wait(long timeout) 当我们使用锁对象在同步代码块中调用此方法,timeout时间过完之前,也处于计时等待 【会释放锁对象】

        * WAITING 【无限等待】:当我们使用锁对象,调用了一个wait()方法,则此线程会无限期等待下去,直到其他的线程叫醒他,才会醒来

        * TERMINATED 【终结】 : 当线程调用的run方法执行完毕,则进入死亡(终结)状态


    * 等待唤醒:
        1. 在同步中
        2. 使用锁对象才能调用wait()或者notify()

## 等待唤醒机制:
        * Object中定义了三个和等待唤醒有关的三个方法:
            * wait() 调用后会释放锁对象,让当前线程陷入等待,直到有其他线程将其唤醒
            * notify() 唤醒其他正在等待的一个线程,先等待的先被唤醒
            * notifyAll() 唤醒全部正在等待的线程

                使用前提:
                1. 同步中
                2. 用锁对象调用这些方法

      * 生产者消费者模型(等待唤醒机制):通过等待和唤醒相关功能让线程之间相互协作完成功能
              * 代码见课上的“吃包子”案例
## 线程池
        * 概述:
                * 如果在线程中执行的任务的次数较多,那么每次开启新线程和销毁线程会对程序性能造成较大的负担
                * 线程池技术实现了对线程的重复利用和统一管理
               
        * 原理:
                * 线程池中包含了一个任务队列和一个线程对象的容器
                * 当线程池在创建的时候会创建多个线程对象
                * 如果任务队列中有多个任务,会依次被线程池中的线程去执行,线程将任务执行完毕后,不会被销毁,而是回到线程池中准备执行下次的任务
               
        * 优点:
                1. 效率高(在使用线程前线程池会提前把线程准备好)
        2. 节约了资源(线程使用完毕不会销毁,而是回到线程池,可以重复使用)
        3. 方便管理线程
    * 代码实现:
            // 创建线程数量固定为3的线程池
        ExecutorService pool = Executors.newFixedThreadPool(3);
                // 提交任务到任务队列中,task是Runnable的实现类对象
        pool.submit(task);
        pool.submit(task);
        pool.submit(task);
        pool.submit(task);
        pool.submit(task);
                // 在线程任务执行完毕后,将线程池关闭
        pool.shutdown();


## 函数式编程思想和lambda:
   * 只在乎完成功能的代码,并不在乎谁完成功能

   * lambda:函数式编程思想的一个具体体现
        可以理解成对匿名内部类的一种优化,但是不等同于匿名内部类

   * 怎么优化:
        可推断即可省略(对于匿名内部类中的代码,能通过上下文推断出来,则就可以省略掉)
                * 既然我们是用lambda去重写接口中的方法,那么方法的声明必须和接口中方法一致

   * lambda表达式的格式:
            (参数列表) -> {完成功能的代码};

            1. 一些参数
            2. 一个箭头
            3. 一段代码

    * 什么时候可以用lambda去改写匿名内部类:
        1. 匿名内部类必须是函数式接口的匿名内部类
        2. 必须有上下文推断

            函数式接口:只有一个抽象方法的接口就是函数式接口(Object中的方法除外)
                    注解:@FunctionalInterface,用于检查一个接口是否是函数式接口

     * lambda表达式的简化格式:
        1. 参数:
            可以省略参数类型,如果有多个类型,要么都省略要么都不省略
            如果只有一个参数,那么小括号也可以省略
        2. 方法体:
            如果方法体中【只有一句代码】,那么大括号可以省略,但是分号也要同时省略
            如果方法体中【只有一句代码】,而且有返回值,那么连着return也可以省略

            注意:大括号、分号、return 这三部分要么都省略,要么都留下

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马