速记
多线程
CountdownLatch
Semaphore 信号量:表示当前系统可用的资源数量,可以用来限制多线程访问特定资源的线程数量;
CyclicBarrier :回环栅栏,类似于 CountdownLatch ,在所有线程在都到达同步点前,先到达的线程都会阻塞等待;
BlockingQueue :线程安全的队列;
java 并发库中的线程同步类:
Exchanger 提供一个同步点,在这个同步点,一对线程相互比较彼此的数据;
Semaphore 信号量,代表当前可用的资源数量;
CountDownLatch 让多个线程进入等待状态,知道其他线程执行完之后再执行,可以用来当计数器,只能使用一次,无法重置;
CyclicBarrier 回环栅栏,类似于 CountdownLatch ,但是自己决定是否可以重复使用,在所有线程在都到达同步点前,可以控制先到达的线程是否阻塞等待;
Phaser 一张可重用的同步屏障,可以可以当作 CountdownLatch 来使用,也可以当作 CyclicBarrier 来使用。他的 phase 、parites、 register 、 arrive 、 await 等等组成的模型可以更灵活地定制多线程间的同步逻辑;
Lock&ReentrantLock 显式锁 ReadWriteLock&ReentrantReadWriteLock 读写锁 Condition 条件锁 StampedLock 第三方库的锁 Guava 的 Monitor 和 RateLimiter
interrupt() & interrupted() & isInterrupted()
锁:锁对象暴露给不可信代码需要使用 私有、不可变对象作为锁对象; private final Object lock = new Object();
集合
LinkedHashMap 是带排序的 HashMap,按照从老到新重新排序;
LinkHashMap#removeEldestEctry(Map.Entry)
该方法用于判断在何时删除最老的<k,v>对。
LinkHashMap#keySet()
按照新老顺序打印集合内的 keySet()
get()会更新 LinkedHashMap 中的<k,v>顺序,被 get() put()的<k,v>都会刷新对应<k,v>的年龄;
LinkList 在 foreach 中删除最后一个和倒数第二个不会抛出异常,其余的都会;
ArrayList 在 foreach 中删除倒数第二个不会抛出异常,其余的都会;
对象的 hashcode() 方法返回的值相同,这些对象作为 hashMap 的 key 时,会产生性能问题。因为 对于 HashMap 中 key 发生碰撞的时候,HashMap 会取出同一个 BucketIndex 桶内的已存储元素逐个通过 hashCode 和 equals 来比较,判断 key 是否存在,如果发生了大量的碰撞 hashMap 的性能是很低下的;
类型&异常
classCastException 的处理:
instanceof;- 集合只存一种类型的对象;
- 捕获异常; 不推荐使用平台或默认的转换;
GC
垃圾回收过程中使用多种回收机制一起处理。 Sweep 清扫,直接清除,会有垃圾碎片; Compact 压缩整理,需要两倍的内存空间,消耗内存;
自动拆\装箱
Integer == int 的时候会发生自动拆箱,Integer.parseInt() == int ,因此变成了比较值;
测试
测试用例五大原则:FIRST
- Fast:执行快,开发人员每次执行小改动都可以快速执行,测试粒度要小;
- Independent:独立,测试程序要相互独立,否则因为一处业务代码的修改,大批的测试程序需要一起修改;
- Repeatable:可重复,测试程序要在不同环境间重复运行,且每次运行结果相同,才能进行有效的回归测试,可重复性的要点在于测试执行与外部环境无关,如果依赖于外部环境(数据库、网络、文件等),随着程序在不同环境间切换,测试很容易失败;
- Self-Validating:自确认。测试结果应是简单的 True/False ,无需人工判断测试结果的正误;
- Timely:及时,单元测试与业务代码同步输出,及时验证,及时 review,不要为了覆盖率后续补充测试用例。测试用例最好在写业务代码之前就开始编写(TDD),通过测试梳理业务功能;UT 应该集成在流水线上,每次修改代码、提交代码都要进行验证,便于及时发现代码缺陷;
IO
Path 中没有 exist()、isExists();
Files 没有 isExists();
RandownAccess 类继承于 Object 类;不是 InputStream 或 OutputStream 的子类,也不同于 FileInputStream 和 FileOutputStream;
JDBC
String sql = "select * from product where id = " + Integer.parseInt(request.getParameter("id"));
这里由于使用了 Integer.parseInt() 作为限制,所以 参数类型实际上已经定死是 int 了,不能再构造除了我们需要的以外的 SQL 语句了,不会发生 SQL 注入,如果传入别的参数会产生 NumberFormatException 异常;
重写\重载
子类重写父类方法必须满足以下条件:
- 父类的方法在子类中必须可见(
public、probect) 2.子类和父类的方法必须是实例方法,如果父类是static方法、而子类是实例方法,或者相反都会报错。如果子类和父类都是static方法,那么子类隐藏父类的方法,而不是重写父类方法; - 子类和父类的方法必须要具有相同的函数名称、参数列表,并且子类的返回值与父类相同,或者是父类返回类型的子类型
- 子类方法的访问权限不能小于父类方法的访问权限
- 子类方法不能抛出比父类方法更多的异常
- 不能重写被标识为
final的方法,final方法可以被继承,但是不能被重写
Runtime.exec() 方法相关联的 ProcessBuilder.start() 方法可以用来调用外部程序进程。这些外部程序运行时 Process 对象会产生 错误流、输出流、输入流;
序列化
敏感字段的安全序列化:
- 通过定义
serialPersistentFields数组字段来确保敏感字段被排除在序列化之外;private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("id", String.class)}; - 自定义
writeObject()、writeReplace()、writeExternal()这些函数,敏感信息的字段不参与序列化字节流中; - 通过将敏感字段声明为 transient 使它们不包括在默认的序列化字段列表中;
NIO
NIO 基本函数: flush clear 读写位置复位到 0 ,读模式 -> 写模式; compact flip 写模式 -> 读模式;