57.只针对异常的情况才使用异常
不要在正常的控制中使用异常:
58.对可恢复的情况使用受检异常,对编程错误使用运行时异常
Java程序设计语言提供了三种异常:1.受检异常;2.运行时异常;3.错误;
59.避免不必要地使用受检的异常
60.优先使用标准异常
61.抛出与抽象相对应的异常
异常翻译:
异常链:
62.每个方法抛出的异常都要有文档
63.在细节消息中包含能捕获失败的信息
64.努力将失败保持原子性
失败的方法调用应该使对象保持在被调用之前的状态
对于不可变的对象,失败原子性是显然的;对于可变的对象,在调用方法的时候检测参数的有效性:
65.不要忽略异常
66.同步访问共享的可变数据
67.避免过度同步
68.executor和task优先于线程
Runnable和Callable的区别:Runnable的方法是run()而Callable的方法是call()。
ExecutorService有四种线程池:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
https://www.cnblogs.com/Steven0805/p/6393443.html
https://www.cnblogs.com/Steven0805/p/6393443.html
69.并发工具优于wait()、notify()
自Java1.5之后,Java平台提供了更强大更高级的并发工具
70.线程安全性的文档化
71.慎用延迟初始化
72.不要依赖于线程调度器
73.避免使用线程组
74.谨慎地实现Serializable接口
1.如果你简单地实现了Serializable接口,那么如果不做特殊处理,里面的私有化类型也会被序列化,这就让隐蔽工作变得困难了。
2.增加了出现Bug和安全漏洞的可能性
通常情况下,对象是利用构造器来创建的,序列化机制是一种语言之外的对象创建机制(隐藏的构造器);由于反序列化机制中没有显示的构造器,所以你很容易忘记要确保,反序列化过程必须也要保证所有“由真正的构造器建立起来的约束关系”,而且不允许攻击者访问正在构造过程中的对象的内部信息。
为继承设计的类尽可能不去实现Serializable接口,用户的接口也尽可能不去继承Serializable接口。
内部类不应该实现S接口
75.考虑使用自定义的序列化形式
76.保护性地编写readObject方法
不严格地说,readObject是一个“用字节流作为唯一参数”的构造器。对象进行反序列化的时候,如果面对一个人工仿造的字节流,这时应该为类提供一个readObject方法,该方法会首先调用defaultReadObject方法,然后检查被反序列化后的对象的有效性,如果无效,会抛出异常。
readObject方法实际上相当于另一个公有的构造器,与其他构造器一样,它也需要进行参数的有效性检查与保护性拷贝。
77.对于实例控制,枚举类型优先于readResolve
在jdk中ObjectInputStream的类中有readUnshared()方法,上面详细解释了原因。我简单描述一下,那就是如果被反序列化的对象的类存在readResolve这个方法,他会调用这个方法来返回一个“array”(我也不明白),然后浅拷贝一份,作为返回值,并且无视掉反序列化的值,即使那个字节码已经被解析。
78.考虑用序列化代理代替序列化实例