一、异常处理
异常(Exception)是一种特殊的运行错误,是在程序运行过程中发生、会打断程序正常执行的错误。
1、异常的分类
错误(Error):JVM系统内部错误、资源耗尽等严重情况,错误使用程序无法解决的问题;
违例(Exception):其它因编程错误或偶然的外在因素导致的一般性问题,使用程序可以解决或控制这些问题。
对负数开平方根
空指针访问
试图读取不存在的文件
2、违例(Exception)的分类
编译时异常:在编译时就会检测是否进行了处理的异常,若未进行处理编译不通过;
可以理解为:强制要求必须进行处理的异常。
运行时异常:在编译时不要求处理的异常,是在运行过程中产生的异常。
思考:运行时异常为什么在编译时不要求检测是否处理异常?
语法上,未要求对运行时异常进行处理;
运行时异常(所有的情况),在程序的任何地方都有可能发生,若检测这些异常“是否进行了处理”,很消耗性能,
所以在编译时不对运行时异常进行检测。
3、处理异常
1) 捕获并处理异常 try..catch..finally
语法格式:
try { //选定捕获异常的范围
} catch(ExceptionName1 e1) { //匹配异常(比较与try中捕获的异常类型是否相同),匹配到,就处理异常
} catch(ExceptionName2 e2) {
} ...... {
} finally { //语句结构统一的出口,无条件执行的语句块,不管是否抛出异常
}
try 1
catch 0..n
finally 0..1
多重catch:
try捕获了异常
a)按照catch的书写顺序,依次匹配;
b)若匹配到catch块,执行块中的代码,其后catch块不再匹配;
c)catch块的异常类型遵守“先子类,后父类”(先小范围,后大范围)的规则。
注意:如果try或者catch块有return 指令,finally还是会被执行,流程先跳到finally然后再回到return指令;
若finally也存在return指令,以finally中的为主,finally中的return指令返回值。
思考:final、finalize、finally三者的区别?
2)抛出异常 throw与throws
throws子句
一个方法执行过程,可能出现某种异常,而方法中不能确定如何处理异常,就使用throws声明抛出这类异常;
方法抛出异常,这个异常由方法调用者处理。
语法格式:
[修饰符] 返回值类型 方法名([参数列表]) throws 异常类名1,异常类名2,...异常类名N {
}
throws为什么称为子句?
throws不能单独作为一条语句使用,是嵌入在方法的声明中的,是方法声明的子句。
throw语句
抛出一个异常对象,作用:用于引发一个异常,即手动抛出异常;
可以作为一条语句使用;
语法格式:
throw new 异常类名();
throw 异常对象名;
throw语句的操作数一定是Throwable类类型或Throwable子类类型的一个对象。
4、自定义异常类
定义Exception类的子类,重写getMessage()方法。
作用:Java语言中定义异常类型数量是有限的,不能够完全满足不同领域需求,此时就需要自定义异常类。
比如:根据人员的角色,判断是否对某个类或方法具有访问权限
有权限直接访问;
没有权限抛出异常。自定义一个没有访问权限的异常类NotAccessException
二、集合
集合是将多个元素组成一个单元的对象;
集合是将多个对象组合在一起,对这些对象进行存储、检索等操纵
;
集合中元素均是引用类型,存储的都是对象。
1、集合的分类
规则集 Set
散列集 HashSet 唯一的、无序的(所谓无序是指存储时无序)
链式散列集 LinkedHashSet 唯一的、有序的(元素的插入顺序)
树形集 TreeSet 唯一的、有序的(自然顺序:字母、数字的升序,按照ASCII码)
线性表 List
数组线性表 ArrayList 可重复的,有序的(下标(位置)有序) 底层是数组物理上有序
链表 LinkedList 可重复的,有序的(下标(位置)有序) 底层是链表逻辑上有序
图 Map
散列图 HashMap key唯一的、value可重复的,无序的
链式散列图 LinkedHashMap key唯一的、value可重复的,元素的插入顺序(默认)
元素的访问顺序
树形图 TreeMap key唯一的、value可重复的,有序的(自然顺序)
2、集合架构图
集合根接口Collection
接口Set、List继承Collection
接口Map,是图根接口,与Collection没有关系
详细查看类图
3、ArrayList与LinkedList的区别
ArrayList
底层是可变数组;
中部操作较慢,查询较快;若只是在尾部操作元素(添加、删除),使用ArrayList效率较快。
LinkedList
底层是双向链表
头部、中部操作较快,查询较慢;若是频繁在头部、中部操作元素(添加、删除),使用LinkedList效率较快。
4、使用for each循环遍历集合,集合必须直接或间接实现Iterable接口
5、TreeSet中的元素、TreeMap的key都必须是可以比较大小的来确定元素或key的先后顺序。
第一种: 可比较,实现Comparable接口,重写compareTo()方法。
第二种: 给TreeSet、TreeMap添加比较器, 自定义比较器实现Comparator接口,重写compare()方法
扩展:自定义带泛型的类
具有通用性的类,作为类型使用,比如:变量的类型、返回值的类型
类的定义角度:使某些类型具有通用性,当不确定变量、返回值得类型时,可考虑使用泛型;
类的使用角度:可以限制类型的范围,比如:集合类的泛型,List<String>限制List线性表中只能存储String类型的元素
6、Vector向量
实现List接口,重写List的所有抽象方法;
Vector有自己扩展的方法,比如:addElement();removeElement() removeElementAt(); 详细查看API;
Vector与ArrayList的区别?
Vector:线程安全,效率较慢。
ArrayList:线程非安全,效率较快。
7、Stack栈表
继承Vector类
后进先出(LIFO last in first out)
8、Hashtable 哈希表
此类实现一个哈希表,该哈希表将键映射到相应的值。
Hashtable与HashMap的区别:
Hashtable:
线程安全;
key/value均不允许为空(null)
HashMap:
线程非安全;
key/vlaue可以为空(null)
HashMap是Hashtable的轻量级实现,省略了Hashtable的一些方法,比如:contains(Object value);
9、Arrays类
操作数组的工具类
10、Collections类
操作集合的工具类
作业:
1、设计一个购物车程序
1)创建商品类Goods,属性:编号、名称、单价、数量、生产日期;
2)创建购物车类BuyCar
定义商品库集合GoodsStoreList,并初始化商品;
定义购买商品集合buyGoodsList;
定义方法:
添加商品到购物车的方法; 判断库存是否足够,若库存不足抛出异常("库存不足!")
取消订购的某件商品的方法;
计算应支付金额的方法;
统计商品库剩余的商品的方法;
编号、名称、单价、数量、总价格
总值:¥1000000000
2、使用集合封装商品信息,商品的信息:编号、名称、单价、数量、生产日期
要求:不自定义商品类
定义类GoodsStore;
定义集合goodsList, 提示:存放Map类型对象;
定义添加商品的方法;
定义展示商品的方法。
3、使用集合按国籍对人员进行分类,按国籍名称(中文拼音)进行排序
定义类Person,属性:姓名,性别,国籍,国籍中文拼音, 出生年月;
定义类Country,
定义按国籍方法assortByCountry(); Map<国籍中文拼音, List> 图(国籍中文拼音,线性表(人员))
定义按国籍名称排序方法sortByName(); TreeMap(比较器) 比较器按中文拼音比较
定义展示人员信息的方法
中国
张三 男 1995-12-23
美国
...
韩国
...
日本
...
创建一个包含不同国籍人员信息的集合。
4、设计文件复制程序
定义方法copy(String sourcePath, String targetPath);
复制sourcePath路径指定的文件,根据targetPath路径保存文件;
若文件名重复,仍然保存文件,文件名:原文件 + 时间毫秒数 + 后缀
5、了解MySQL,如何安装MySQL数据库
MySQL服务器
MySQL客户端
6、思考:自定义ArrayList类、LinkedList类
添加元素
修改元素
插入元素
删除元素
遍历元素
查找元素,返回下标
泛型
一、File类
文件和目录路径名的抽象表示形式。
常用方法:
mkdirs();
mkdir();
createNewFiles();
exists();
listFiles();
isDirectory();
isFile();
二、I/O流
输入/输出数据流
1、I/O流分类
按数据格式分类:
字节流 和 字符流
按数据作用(输入、输出)划分:
输入流 和 输出流
2、字节流
字节输入流 InputStream
字节输出流 OutputStream
注意:InputStream和OutputStream均是抽象类,不能被实例化。
注意:过滤流,是装饰模式的实现。继承是对类的扩展,装饰是对对象的扩展。
3、字符流
字符输入流 Reader
字符输出流 writer
注意:Reader和Writer均是抽象类,不能被实例化。
注意:底层是字节流。
4、装饰模式
在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。
它是通过创建一个包装对象,也就是装饰来包裹真实的对象
三、线程Thread
1、进程与线程
进程:进程一个程序的执行过程,程序执行时均开启进程,程序执行结束,结束进程;
进程是系统进行资源分配和调度的一个独立单位;
每个进程都有自己独立的内存空间、一组系统资源。
线程:线程是进程中某个单一顺序的控制流;
线程也被称为轻量级进程;
线程是程序执行流的最小单元;
一个进程中的多个线程共享一块内存空间和一组系统资源。
每个线程都有一个独立的栈与计数器,共享堆与方法区。
进程与线程之间的关系:
一个进程中至少有一个线程,一个线程属于一个进程;
线程决定进程的生命周期,一个进程的执行,由多个线程进行任务的处理;
多个线程可以并发执行(同时执行)。
多线程:多线程是指在同一应用程序中,能同时运行多个任务程序。
程序可以同时运行多个不同的线程,执行不同的任务;
每个线程有独立的栈和程序计数器;
线程切换开销小。
2、创建线程
1)继承Thread类
2)实现Runnable接口
均需要重写run()方法;
run()方法是线程的入口函数,相当于类的main()函数;
run()方法决定线程的生命周期,run()执行结束线程也执行结束。
3、创建线程对象
1)继承Thread类 —— 直接实例化 new ***Thread();
2) 实现Runnable接口 —— Runnable实现类的对象,作为Thread类构造方法的参数,构建一个Thread对象;
new Thread(new ***Runnable());
4、启动线程
线程对象.start();
5、线程的执行
线程的运行必须CPU上执行(计算机做任何事情,均是由CPU发送指令);
CPU(单核)在同一时间点只能执行一个线程;
多线程的问题:
多个线程并发执行,同时执行;意思是:同一个时间段多个线程并发执行,均会执行,也可以说是同时执行;
多个线程以抢占的形式获得CPU一段时间的处理权,该段时间非常短,称为时间片;
抢占CPU资源、抢占CPU时间片 ——> 抢占CPU一段时间的处理权。
多线程执行,通过共享并抢占CPU资源实现的(通过共享CPU资源来实现的,对CPU资源的利用是抢占式的)。
6、线程的结束
1)线程正常结束,run方法执行完毕;
2)调用stop()或destroy()强制终止线程,已过时,不提倡使用;
3)设置中断标志,使用interrupt()方法,当线程发生阻塞(不能抢占资源),抛出InterruptedException异常。
线程常用方法:
yield(); //暂停当前正在执行的线程对象,并执行其他线程
sleep(long millis); //当前正在执行的线程休眠millis毫秒
作业:
1、获得指定目录下的所有文件,保存子路径中的文件
2、设计文件管理器,可选择文件,保存到指定目录
扩展:选择文件保存目录
3、使用线程设计一个定时器,每过5秒钟向文件(log.txt)写入日志数据:
2016年08月16日 18:06:06 系统运行正常!
4、扩展:使用线程设计一个闹钟程序,使用闪动效果代替声音:
设置闪动的时间;
到达设置的时间,闪动三次。
5、思考:线程五个状态之间切换,如何切换。
6、思考:自定义ArrayList类、LinkedList类
添加元素
修改元素
插入元素
删除元素
遍历元素
查找元素,返回下标
泛型
一、线程Thread
1、进程与线程
进程:进程一个程序的执行过程,程序执行时均开启进程,程序执行结束,结束进程;
进程是系统进行资源分配和调度的一个独立单位;
每个进程都有自己独立的内存空间、一组系统资源。
线程:线程是进程中某个单一顺序的控制流;
线程也被称为轻量级进程;
线程是程序执行流的最小单元;
一个进程中的多个线程共享一块内存空间和一组系统资源。
每个线程都有一个独立的栈与计数器,共享堆与方法区。
进程与线程之间的关系:
一个进程中至少有一个线程,一个线程属于一个进程;
线程决定进程的生命周期,一个进程的执行,由多个线程进行任务的处理;
多个线程可以并发执行(同时执行)。
多线程:多线程是指在同一应用程序中,能同时运行多个任务程序。
程序可以同时运行多个不同的线程,执行不同的任务;
每个线程有独立的栈和程序计数器;
线程切换开销小。
2、创建线程
1)继承Thread类
2)实现Runnable接口
均需要重写run()方法;
run()方法是线程的入口函数,相当于类的main()函数;
run()方法决定线程的生命周期,run()执行结束线程也执行结束。
3、创建线程对象
1)继承Thread类 —— 直接实例化 new ***Thread();
2) 实现Runnable接口 —— Runnable实现类的对象,作为Thread类构造方法的参数,构建一个Thread对象;
new Thread(new ***Runnable());
4、启动线程
线程对象.start();
5、线程的执行
线程的运行必须CPU上执行(计算机做任何事情,均是由CPU发送指令);
CPU(单核)在同一时间点只能执行一个线程;
多线程的问题:
多个线程并发执行,同时执行;意思是:同一个时间段多个线程并发执行,均会执行,也可以说是同时执行;
多个线程以抢占的形式获得CPU一段时间的处理权,该段时间非常短,称为时间片;
抢占CPU资源、抢占CPU时间片 ——> 抢占CPU一段时间的处理权。
多线程执行,通过共享并抢占CPU资源实现的(通过共享CPU资源来实现的,对CPU资源的利用是抢占式的)。
6、线程的结束
1)线程正常结束,run方法执行完毕;
2)调用stop()或destroy()强制终止线程,已过时,不提倡使用;
3)设置中断标志,使用interrupt()方法,当线程发生阻塞(不能抢占资源),抛出InterruptedException异常。
7、线程的状态
1)新建状态
创建一个线程对象,此时线程处于新建状态;
调用start()方法,线程进入就绪状态。
2)就绪状态
该状态的多个线程,抢占CPU资源,即获得CPU处理权;
若线程抢占到CPU资源,进入运行状态。
3)运行状态
执行run()方法;
进入阻塞状态
sleep();线程休眠一段时间
join();线程等待另一线程执行结束
wait();等待被通知唤醒
suspend();挂起线程
等待IO资源(来至于网络的资源)
等待同步锁
进入结束状态
run()执行完毕
抛出异常,阻断了run()方法执行
stop()、destroy()强制终止线程
返回就绪状态
时间片用完,失去CPU处理权,返回就绪状态;
yield(); 使线程让出CPU资源,进入就绪状态;
4)阻塞状态
进入就绪状态
休眠时间结束
等待的线程执行结束
notify()、notifyAll()唤醒wait()使其等待的线程
resume();激活挂起的线程
获得IO资源
获得同步锁
5)结束状态(死亡状态)
注意:新建、就绪、运行、阻塞均可直接进入结束状态。
8、线程同步:确保一个资源对象同时只能被一个线程访问,解决资源冲突的有效手段。
资源:资源对象,多个线程访问同一个对象;
资源冲突:多个线程访问同一个资源对象,发生了数据冲突,这种情况称为资源冲突;
临界区:资源对象中可能发生资源冲突的区域(方法);
线程安全:多个线程访问同一个资源对象,未发生资源冲突,就说:资源对象是线程安全的;
如何解决资源冲突?
线程同步synchronized
使用“锁机制”实现
一个线程在访问资源对象时,对资源对象进行加锁,其他访问资源的线程进入阻塞状态,
等待线程访问结束,释放资源锁。
锁的释放:
方法或同步块执行结束;
wait();执行该方法当前线程进入阻塞状态,让出CPU资源,释放资源对象的锁。
实现线程同步的两种方法:
同步方法
方法声明添加synchronized修饰符
同步语句块
synchronized(对象名) {
......
}
注意:线程同步会降低程序的性能,增加程序运行所花费的时间。
9、线程之间的交互
wait(); 当前线程等待
notify(); 唤醒等待队列中的一个线程
notifyAll(); 唤醒等待队列中的所有线程
以上三个方法必须在同步方法或同步语句块中。
10、守护线程
所有非守护线程执行结束后,守护线程会立即结束,不管run()是否执行完毕。
setDaemon(true);标记一个线程为守护线程,必须启动前标记线程为守护线程。
11、线程组ThreadGroup类
线程组是多个线程的集合;
线程组中可以包含线程组;
线程组可以同时挂起、激活或停止组中所有的线程;
线程组不能启动组中线程,而是手动启动每一个线程,线程对象.start();
线程常用方法:
yield(); //暂停当前正在执行的线程对象,并执行其他线程
sleep(long millis); //当前正在执行的线程休眠millis毫秒
interrupt(); //设置中断标识
join(); //当前线程等待另一线程执行结束
setDaemon(); //将该线程标记为守护线程或用户线程
isAlive(); //测试线程是否是活动状态,就绪、运行、阻塞属于活动状态
setPriority(int newPriority); //更改线程优先级,优先级1..10,最小是1,最大10,默认是5
getPriority(); //获得线程优先级
资源类中方法:
wait();
notify();
notifyAll();
二、线程池,是一种控制系统线程执行数量,合理利用系统资源,提高系统性能的多线程处理形式。
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。
线程池线程都是后台线程。
作用:限制系统中线程的数量。
思考:线程池如何控制管理?
线程池中线程的数量有限,线程被重复使用;
使用线程池,添加到线程池中的是任务,而非线程;
固定大小线程池:
第一次:添加一个任务,线程池自动启动一个线程,执行这个任务;
第二次:添加一个任务,检查池检测线程数量是否达到上限
线程数量未达到上限,线程池自动启动一个新线程,执行这个任务;
线程数量达到上限
存在空闲线程:
空闲线程执行任务;
不存在空闲线程:
任务添加到等待队列中,直到有空闲线程(有线程执行任务结束),执行等待队列中的第一个任务。
线程池的执行过程:
核心线程数、最大线程数、线程的空闲时间、等待队列
添加任务到线程池,若池中线程数量<核心线程数,创建并启动一个线程执行任务;
添加任务到线程池,若池中线程数量=核心线程数,任务添加到等待队列中,等待空闲线程(等待有线程执行结束),
空闲线程执行等待队列中第一个任务;
添加任务到线程池,若无空闲线程、等待队列已满,池中线程数<最大线程数,创建并启动一个新线程执行任务;
若无空闲线程、等待队列已满,池中线程数=最大线程数,抛出异常。
注意:线程数>核心线程数,Java运行时系统回收空闲线程(空闲的时间>规定的线程空闲时间),直到线程数=核心线程数
时,就不再回收,无论线程是否空闲。
1)常用线程池
单例线程池,只有一个线程执行任务;
有界(固定大小)线程池,多个线程执行任务,线程的数量有限;
可缓存线程池(不限制线程池大小),默认情况下,空闲线程1分钟未执行任务,会被回收;
无界线程池,支持定时以及周期性执行任务的需求。
为什么要用线程池?
1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下
(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。
真正的线程池接口是ExecutorService。
比较重要的几个类:
ExecutorService 真正的线程池接口。
ScheduledExecutorService 能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。
ThreadPoolExecutor ExecutorService的默认实现。
ScheduledThreadPoolExecutor 继承ThreadPoolExecutor的ScheduledExecutorService接口实现,
周期性任务调度的类实现。
作业:
1、使用线程的交互模拟账户金额的存取程序。
2、下载MySQ安装包 服务器Server
64位
32位
一、JDBC(Java Data Base Connectivity,java数据库连接)
是一种用于执行SQL语句的Java API;
可以为多种关系数据库提供统一访问,跨平台(数据库管理系统DBMS);
它由一组用Java语言编写的类和接口组成。
1、获得数据的链接,Connection接口
1)DriverManager.getConnection();获取数据库链接
2) Datasource接口的实现类获得数据库链接
MySQL驱动包提供MysqlDatasource类实现Datasource接口
参数:
driverClass:com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo
username: root
password: 123
2、通过链接创建执行SQL语句的对象,Statement接口
查询语句:
select
获得数据结果集,ResultSet接口
遍历提取数据
更新语句:
insert
update
delete
更新表中数据,返回影响行数
3、结果集的元数据,元数据基本上是描述列的类型和属性信息,也称为结果集的列模型
ResultSetMetaData接口
4、PreparedStatement接口
表示预编译的 SQL 语句的对象。
SQL语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。
6、批处理,同时执行多条SQL语句。
7、可配置的数据源
1)使用.properties文件,配置数据源的基本信息;
2) 使用Properties类读取配置文件中的数据。
练习:
1、修改Datasource数据源的基本信息为可配置的;
2、使用DDL语句创建学生表
字段:ID、学号、姓名、性别、班级、出生年月、操作时间
创建数据源类Datasource,用于获得数据库的链接
要求:数据源属性可配置
创建数据访问公共接口IDataService及其实现类DataServiceImpl
定义查询数据表方法
定义插入数据方法
修改数据方法
删除数据方法
扩展:批量删除
3、扩展:思考数据库链接池如何实现
控制链接数
一、事务管理
1、什么是事务?
事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit);
事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成;
事务同时执行多种数据库操作,保证这“多种操作”作为一个整体操纵数据库,要不就一起成功,要不就一起失败。
只要有一种操作失败,所有操作均失败,之前操作成功的会被撤销。
2、事务的特性:
原子性
一致性
隔离性
持久性
3、JDBC中事务处理:
1)自动事务处理
默认的
2)手动事务处理
关闭自动提交事务setAutoCommit(false);
手动提交事务commit();
或出现错误后,手动回滚事务rollback();
二、JDBC创建表格
Statement中的executeUpdate()方法,直接执行DDL语句
三、CallableStatement接口
用于执行 SQL 存储过程的接口
四、反射机制
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
1、常用类
Class 类
forName(String className); //根据类名加载类,获得类型信息封装对象
newInstatnce(); //创建对象
getDeclaredField(String name); //返回指定名称的Field(属性)对象
getDeclaredFields(); //返回所有的Field对象
getDeclaredMethod(String name, Class<?>... parameterTypes);
getDeclaredMethods();
getConstructor(Class<?>... parameterTypes);
getConstructors();
Field 属性类
get(Object obj);
set(Object obj, Object value)
Method 方法类
invoke(Object obj, Object... args); //执行方法
Constructor 构造器类
newInstance(Object... initargs); // 创建对象,执行构造方法,初始化对象
ORM(对象关系映射)框架,普遍使用到反射机制。