java之异常???
异常本身就是一个类,处理方式是中断。
异常体系:
Throwable体系:异常的根类是java.lang.Throwable类
Error:严重错误Error,无法通过处理的错误,只能事先避免,好比绝症。必须修改源代码了,程序才能继续执行。
Exception:表示异常(编译期异常),程序得了一个小毛病,处理掉,程序可以继续执行。其下还有一个子类RuntimeException:运行期异常。无须处理。
异常的处理:
throw:关键字,在指定的方法中抛出指定的异常
格式:
throw new xxxException(“异常产生的原因”);//新建的一个对象
注意:
1、throw关键字必须写在方法的内部
2、throw关键字后面的new对象必须是Exception或者Exception子类对象
3、抛出后,就必须处理
new后面若是RuntimeException或者RuntimeException子类对象,可以不处理,默认交给JVM处理(打印异常对象,中断程序)
new后面是编译异常(写代码的时候报错),我们就必须处理,要么throws要么try...catch
objects非空判断:里面有个静态方法
public static <T> T requireNonNull(T obj)查看指定引用对象不是null
声明异常throws:
异常处理的第一种方式,交给别人处理
作用:会把异常对象声明抛出方法的调用者处理(自己不处理,给别人处理),最终交给JVM处理---->中断处理。
使用格式:在方法声明时使用
修饰符 返回值类型 方法名(参数列表)throws xxxException,...{
throw new xxxExcepton("产生的原因");
...(其他异常)与throws后面是一样的,声明什么异常就抛出什么异常
}
注意事项:
1、必须写在方法声明中
2、throws抛出的对象必须是Exception或者Exception子类对象
3、方法内部如果出现了多个异常对象,那么throws后边也必须声明多个异常
如果抛出的多个异常对象有子父类关系,那么直接处理父类异常即可
4、调用了一个声明抛出的异常的方法,就必须处理声明的异常
要么继续使用throws声明抛出,交给方法的调用者处理,最终交给jvm
要么try...catch自己处理异常
捕获异常:try..catch:
异常处理的第二种方式,自己处理异常
格式:
try{
可能产生的异常代码
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
异常处理逻辑,产生异常对象之后,怎么处理异常对象,一般在工作中,会将异常的信息记录到一个日志中
}
.....
catch(异常类名,变量名){
}
注意:
1、try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象
2、如果try中产生了异常,就会执行catch中的异常处理逻辑。执行完毕后,继续执行try...catch后的代码
如果try中没有产生异常就不会执行catch中的代码,而是执行try中的代码及后续代码
如何获取异常信息呢?Throwable类三个静态方法
public String getMessage() :返回throwable简短描述
public String toString() :返回throwable详细消息字符串,重写object类的toString方法
public void printStackTrace() :jvm打印异常对象,默认的方法,打印的异常最全面
finally代码块:
格式:跟try一起使用的
try{
}catch(){
}finally{
//无论是否出现异常都会执行
}
注意:
1、一般用于资源回收
多个异常使用捕获又该如何处理呢?
1. 多个异常分别处理。
2. 多个异常一次捕获,多次处理。
3. 多个异常一次捕获一次处理。
异常注意事项:
1、如果finally有return语句,永远返回finally中的结果,一般情况下要避免该情况.,返回一个数也没有意义,final一般是作为释放资源用的。
2、父类异常什么样,子类异常就是什么样。
自定义异常:
格式:
public class xxxExcepition extends Exception | RuntimeException{
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息。
多线程:
并发与并行概念?
并发:指交替执行。
并行:同时执行。脑补两个CPU的场景。其实现在大多都是多核CPU
线程与进程概念?
进程:进入到内存中的程序叫进程
线程:应用程序到cpu的执行路径,是进程中的一个执行单元,负责程序执行
线程调度?
1、分时调度:轮流使用cpu
2、抢占式调度:优先级高先执行,相同,会随机选择一个执行。java也是抢占式调试。
主线程概念?
执行主方法的线程。主方法也是就main。
创建多线程java程序?
第一种方式:创建thread子类。java.lang.thread,描述线程类,要实现多线程就要继承它
步骤:
1、创建一个Thread子类
2、重写其子类的run方法,设置络任务(开启线程要做什么)
3、创建Thread类的子类对象
4、调用Thread类中的start方法,开启新的线程执行run方法。
第二种方式:实现Runnable接口,场景是打算通过某一线程执行其实现类
步骤:
1、创建一个Runable接口实现类
2、在实现类中重写Runable接口的run方法,设置线程任务
3、创建一个Runable接口的实现类对象
4、创建Thread类对象,构造方法中传递Runable接口的实现类对象
5、调用Thread类中的start方法,开启新的线程执行run方法
实现Runable接口创建多线程的好处?
1、避免单继承的局限性,实现Runable接口,还可以继承其他的类,实现其他接口
2、增强了程序扩展性,降低了程序的耦合性(解耦),把设置线程与开启线程进行了分离(解耦),实现类中,重写了run方法,用来设置线程任务,创建Thread类对象,调用start方法,用来开启新线程。
匿名内部类方式实现线程的创建?
作用:简化代码
把子类继承父类,重写父类的方法,创建子类对象合一步完成
把实现类/实现类接口,重写接口中的方法,创建实现类对象合一步完成
格式:
new 父类/接口(){
重复父类/接口中的方法
}
Thread类的静态方法?
public String getName() :获取当前线程名称。
public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
public void run() :此线程要执行的任务在此处定义代码。
public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
线程同步机制:访问共享数据就会出现线程安全问题。
解决:
1、同步代码块
格式:
synchronized(锁对象){
可能会出现线程安全问题的代码;
}
注意:
1、通过代码块中的锁对象(相等于嵌入式同步里信号量为1的情况),可以使用任意的对象如object类对象。
2、但必须保证多个线程使用的锁对象是同一个
3、锁对象作用:把同步代码锁住,只让一个线程在同步代码块中执行。
2. 同步方法。
使用步骤:
1、把访问了共享数据的代码抽取出来,放到一个方法中
2、在方法上添加syncranized修饰符
格式:就是定义方法
修饰符(如public) synchranized 返回值类型 方法名(参数列表){
可能会出现线程安全问的代码
}
原理:同步的锁对象,就是实现类对象new RunnableImpl(),也就是this
3. 锁机制。
java.util.concurrent.locks.Lock接口。
lock接口的方法:
public void lock() :获取锁
public void unlock() :释放锁。
使用步骤:java.util.concurrent.locks.Reentrontlock 实现了lock接口
1、在成员位置创建一个Reentrantlock对象
2、在可能出现安全问题的代码前调用lock获取锁
3、在可能出现安全问题的代码后调用unlock 释放锁。
等待唤醒机制:
线程的状态:如下图:
Timed Waiting:计时等待,执行sleep(带参)方法
BLOCKED(锁阻塞):接同步时的等待锁。
Waiting(无限等待):线程之间的通讯,与嵌入式的通讯的内容是一样的。
过程:创建一个消者费线程
调用wait方法,放弃cpu的执行,进入到Watting方法(无限等待)
创建一个生产者线程
调用notify方法,唤醒消费者线程
注意:
生产与消费者线程必须使用同步代码包裹起来,保证等待和唤醒只能有一个在执行
同步使用的锁对象必须保证唯一。
只有锁对象才能调用wait和notify方法
Object类中的方法
void wait():在其他线程调用此对象的notify()方法或notifyAll()方法前,导致当前线程等待
void notify():唤醒在此对象监视器上等待的单个线程,会继续执行wait方法之后的代码。
进入到TimeWaiting(计时等待)有两种方式
1、使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Blocked状态
2、使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,线程睡醒后进入到Runnable/Blocked状态。
唤醒方法:
void notify()唤醒在此对象监视器上等待的单个线程
void notifyAll()唤醒在此对象监视器上等待的所有线程。
线程池:底层原理:一个容器
当程序第一次启动的时候创建多个线程保存到一个集合中,其中的线程可以反复使用。用线程池来管理线程。
实现:jdk1.5后 java自带线程池
java.util.concurrent.Executors:线程池工厂类,用来生成线程池
Executors类中的静态方法:
static ExecutorService newFixedThreadPool(int nThreads)创建一个可重用固定线程数的线程池
参数:
int nThreads:创建线程池中包含的线程数量
返回值:
ExcutorService接口,返回的是ExecuorService接口的实现类对象
java.util.concurrent.ExecutorService:线程池接口
用来从线程池中获取线程,调用start方法执行线程任务
submit(Runnable task)提交一个 Runnable 任务用于执行
关闭/销毁线程的方法:
void shutdown();
线程池的使用步骤:
1、使用线程池的工厂类ExecutorService newFixedThreadPool生产一个指定线程数量的线程池
2、创建一个类,实现Runnable接口 ,重写run方法,设置线程任务
3、调用ExecutorService中的方法submit传递线程任务(实现类),开启线程,执行run方法
4、调用shutdown销毁线程池(不建议执行)
函数式编程思想:
有输入量、输出量的一套计算方案,也就是"拿什么东西做什么事情“。
面向对象思想:做一件事情,得找一个能解决这个事情的对象,调用对象方法完成事情。
函数式编程思想:只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程。
Lambda表达式的标准格式:
1、一些参数
2、一个箭头
3、一段代码
(参数列表) ---> {一些重写方法的代码}
():接口中抽象方法的参数列表,没有参数就空着,多个参数使用逗号分隔;参数的数据类型可以省略,如果参数只有一个,类型和小括号()都可省略
--->:传递的意思,把参数传递给方法体{}
{}:重写接口的抽象方法的方法体。如果只有一行代码,{}和;return(有返回) 都可省略。
省略规则就是可推导可省略。
Lambda的使用前提:
1. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。
2. 使用Lambda必须具有上下文推断。