仅限个人学习总结,不适用参考。
参考文献:
《Java 核心技术(第 10 版)》
journaldev
异常
逐级传递;若未找到异常处理者,终止程序,抛出异常。
Java 语言规范将派生于 Error 类或 RuntimeException 类的所有异常称为非受查异常( unchecked ) , 所有其他的异常称为受查异常( checked ) 编译器将核查是否为所有的受査异常提供了异常处理器。
断言检查只用于开发和测试阶段
创建文件三种方法
-
file.createNewFile()
;
分 absolute、relative 两种;要求路径已存在,否则抛出 IOException -
创建并写入数据,要求同上
FileOutputStream.write(byte[] b){
String data="some data";
FileOutputStream fos=new FileOutputStream("name.txt");
fos.write(data.getBytes());
fos.flush();
fos.close();
}
复制代码
- 不必担心关闭 IO 资源
Files.write()
String data="some data";
Files.write(Paths.get("name.txt"),data.getBytes());
复制代码
接口与回调(callback)
回调:指出某事件发生时,执行的动作
内部类(inner class)
- 访问外部类的数据,包括私有数据
- 对同一包中其他类隐藏
- 回调函数、匿名内部类
匿名内部类:只创建类的一个对象
泛型(generic)
聚集任意类型的对象
ArrayList
"String" 类型参数(type paraments): 使程序具有更好的可读性和安全性
自定义泛型
-
泛型类
Class Pair
"T" 类型变量 -
泛型方法
static T methodName(){
...
}
复制代码
调用泛型方法绝大多数情况不用指明 T,由编译器推断
泛型类型限定(bound)
static T min(){
...
}
复制代码
多限定
static T min(){
...
}
复制代码
桥方法
public class Pair<T> {
private T first;
private T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public void setSecond(T second) {
this.second = second;
}
...
}
复制代码
类型擦除后
public class Pair<Object> {
private Object first;
private Object second;
public Pair(Object first, Object second) {
this.first = first;
this.second = second;
}
public void setSecond(Object second) {
this.second = second;
}
...
}
复制代码
问题
class DateInterval extends Pair<LocateDate>{
public void setSecond(LocateDate second){...}
}
复制代码
此时有
DateInterval.setSecond(LocateDate s)
DateInterval.setSecond(Object s)
复制代码
编译器在 DateInterval 生成桥方法
public void setSecond(Object second){
setSecond((LocateDate) second);
}
复制代码
泛型事实:
- 虚拟机中没有泛型,只有普通的类和方法。
- 所有的类型参数都有它们的限定类型替换。(默认 Object)
- 桥方法被合成来保持多态。
泛型继承 Pair
和 Pair
无继承关系
但泛型可以实现接口 例如 ArrayList
集合
基本接口:Collection Map
并发(concurrent)
进程、线程。
二者本质的区别在于每个进程拥有自己的一整套变量,线程则共享变量。
Runnable r = ()->{
...
}
复制代码
创建一个执行 run 方法的新线程
Thread.start()
复制代码
当线程 run 方法执行方法体中的最后一条语句后,并 return 返回 或者出现没有捕获的异常时,线程终止。
产生 InterruptedException 异常:
- 线程被阻塞,就无法检测中断状态,产生 InterruptedException 异常
- 在中断状态被置位时调用 sleep 方法,它不会休眠。相反,它将清除这一状态并拋出 InterruptedException
同步
如果能保证线程在失去控制之前完成任务,那么就不会出现错误。
加锁
ReentrantLock
class Bank{
private ReentrantLock bankLock = new ReentrantLock();
bankLock.lock();
try {
System.out.print(Thread.currentThread());
accounts[from] -= amount;
System.out.printf(" %10.2f from %d to %d", amount, from, to);
accounts[to] += amount;
System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
} finally {
bankLock.unlock();
}
}
复制代码
假定第一个线程调用 transfer , 在执行结束前被剥夺了运行权。
假定第二个线程也调用 transfer , 由于第二个线程不能获得锁, 将在调用 lock 方法时被阻塞 。 它必须等待第一个线程完成 transfer 方法的执行之后 才能再度被激活。 当第一个线程释放锁时 , 那么第二个线程才能开始运行
条件变量
不满足条件时阻塞线程
await()
signalAll()
复制代码
调用 signalAll()
不会立即激活一个等待线程。 它仅仅解除等待线程的阻塞 , 以便这些线程可以在当前线程退出同步方法之后 , 通过竞争实现对对象的访问
总结锁和条件:
- 锁用来保护代码片段,任何时刻只能有一个线程执行被保护的代码
- 锁可以管理试图进入被保护代码段的线程
- 锁可以拥有一个或多个条件对象
- 每个条件对象管理那些已经进入被保护的代码段但还不能运行的线程
public synchronized void method(){
....
}
复制代码
等价于
public void method(){
this.intrinsicLock.1ock() ;
try{
...
}
finally {
this.intrinsicLock.unlock();
}
}
复制代码
忠告:如果 synchronized 关键字适合你的程序,那么请尽量使用它, 这样可以减少编写的代码数量,减少出错的几率 。
何时使用同步?
如果向一个变量写入值,而这个变量接下来可能会被另一个线程读取; 或者,从一个变量读值,而这个值可能是之前被某一线程写入的,此时必须使用同步。
volatile
为实例域的同步提供了一种免锁机制
例
public boolean done;
public synchronized boolean isDone(){return done;}
public synchronized void setDone(done){this.done=done;}
...
public volatile boolean done;
public boolean isDone(){return done;}
public void setDone(done){this.done=done;}
复制代码
多线程
Timer TimerTask
典型代码
{
TimerTask timerTask = new MyTimerTask();
Timer timer = new Timer(true);
// 每隔 10s 调度一次
timer.scheduleAtFixedRate(timerTask, 0, 10 * 1000);
}
复制代码
- time.cancel() 可以终止 timer 和相关调度任务,但不干扰当前任务。
- 守护进程在所有用户进程终止后终止。
- time.scheduleAtFixedRate() 调度时间应略大于任务线程执行时间, 否则任务线程队列会越来越长。
线程池
- ExecutorService Exceutors 使用 ThreadPoolExecutor 提供了 ExecutorService 的实现。
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(worker);
class Worker implements Runnable{
...
}
复制代码
- ThreadPoolExecutor 更全
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor();
poolExecutor.execute(worker);
复制代码
Callable & Future
Callable 比 Runnable 多了返回值, Callable 使用泛型定义返回类型,Callable 并行运行,使得我们必须等待返回对象。
Callable 返回 Future,它使我们能够查询 Callable 状态,get()可得到返回值。