just for mark.
1. 使用@throws标识,对违反参数限制时进行抛出异常。
2. 非公有方法通常使用断言(assertion)来检查参数。
1. 对于构造器的每个可变性参数进行保护性拷贝。
2. 对于参数类型可以被不可信任方子类化的参数,不要使用clone方法进行保护性拷贝。
3. 另一种方案是,给客户端返回对象(数组、集合等)使用不可变视图。
1. 谨慎地选择方法的名称。
2. 不要过于追求提供便利的方法。
3. 避免过长的参数列表。
1. 要调用哪个重载方法是在编译时做出决定的。
2. 永远不要导出两个具有相同参数数目的重载方法。
3. 对于每一组重载方法,至少有一个对应的参数在两个重载方法中具有“根本不同”的类型。
1. 不必改变具有final数据参数的每个方法;只当确实是在数量不定的值上执行调用时才使用可变参数。
1. 文档注释应该列出这个方法的所有前置条件,和后置条件。还有副作用。
2. 常用的@param, @return, @throws, {@code}
3. 线程安全性与可序列化性的注释
1. 在第一次使用变量的地方进行声明。
2. 几乎每个局部变量的声明都应该包含一个初始化表达式。
3. 使方法小而集中。
1. for-each性能没有损失。
2. 三种情况无法使用for-each: 过滤(调用remove),转换,平行迭代。
1. 使用标准类库,例如:Random.nextInt(int);
1. 不适合用于货币计算
2. 使用BigDecimal、int或long
1. 区别:
一、基本类型只有值,而装箱基本类型则具有与它们的值不同的同一性。
二、基本类型只有功能完备的值,而装箱类型除了它对应基本类型的所有功能值之外,还有个非功能值:null。
三、基本类型比装箱基本类型更节省时间与空间。
2. 当在一项操作中混合使用基本类型与装箱基本类型时,装箱基本类型就会自动拆箱。如果null对象引用被自动拆箱会抛出NullPointerException。
1. 字符串不适合替代其他的值类型。
2. 字符串不适合替代枚举类型。
3. 字符串不适合替代聚集类型。
4. 字符串不适合代替能力表。
1. 连接多个字符,考虑使用StringBuilder
1. 反射的代价:
一、丧失了编译时类型检查的好处。
二、执行反射访问所需要的代码非常笨拙和冗长。
三、性能损失。
2. 使用反射的情况:付出少许代价,但是可以获得许多好处。
1. 编写好的程序而不是快的程序。
2. 努力避免那些限制性能的设计决策。
3. 考虑API设计决策的性能后果。
4. 为好的性能而对API进行包装,这是不好的做法。
1. 异常只用于异常的情况下,它们永远不应该用于正常的控制流。
2. 设计良好的API不应该强迫它的客户端为了正常的控制流而使用异常。
1. 如果期望调用者能够适当地恢复,对于这种情况应该使用受检的异常。
2. 运行时异常与错误,属于不可恢复的情形,继续执行下去有害无益。如果程序没有捕捉到这样的可抛出结构,将会导致当前线程停止,并出现适当的错误方法。
3. 用运行时异常来表明编程错误。
1. IllegalArgumentException和IllegalStateException
2. 值得了解的:ConcurrentModificationException,UnsupportOperationException
1. 更高层次的实现应该捕捉低层次的异常,同时抛出可以按照高层抽象进行解释的异常。(异常转义)
2. 低层次异常传到高层次异常。(异常链)
1. 为了失败,异常的细节信息应该包含所有“对该异常有贡献”的参数和域的值。
1. 一般而言,失败的方法调用应该使对象保持在被调用之前的状态。
2. 在执行操作之前检查参数的有效性。
3. 编写恢复代码。
1. 为了线程之间进行可靠的通讯,也为了互斥访问,同步是必要的。
2. volatile使用,确保任何线程在读取该域的时候都将看到最近写入的值。
3. 将可变数据限制在单个线程中。
1. 为了避免活性失败和安全性失败,在一个被同步的方法或者代码块中,永远不要放弃对客户端的控制。
2. 在同步区域之外调用外来方法(开放调用)。
3. 同步区域内做尽可能少的工作。
1. ExecutorCompletionService: 在任务完成时逐个地获取这些任务的结果。
2. 小程序、轻负载的,可以使用Executors.newCachedThreadPool(大负载不适用,因为被提交的任务没有排成队列,而是直接交给线程执行,如果没有线程可用,就会创建新的线程)。
3. ScheduledThreadExecutorPool代替java.util.Timer。
1. java.util.concurrent的工具分为三类:Executor Framework、并发集合(Concurrent Collection)、同步器(Synchronizer)。
2. 优先使用ConcurrentHashMap。
3. 注意线程饥饿死锁。
4. 对于间歇式的定时,始终应该优先使用System.nanoTime,而不是System.currentTimeMills。
1. 除非绝对必要,否则不要这样做。
2. 如果出于性能的考虑而需要对静态域使用延迟初始化,使用lazy initalization holder class 模式。
3. 如果出于性能的考虑而需要对实例域使用延迟初始化,就使用双重检查模式(double-check idiom)。
4. 如果可以接受重复初始化的实例域,可以使用single-check idiom。
1. 可运行线程的平均数量不明显多于处理器的数量。(注意是可运行)
2. 如果线程没有在做有意义的工作,就不应该运行。(不应该一直处于busy-wait状态)
3. 线程优先级是Java平台上最不可移植的。
1. 最大的代价是,一旦一个类被发布,就大大降低了“改变这个类的实现”的灵活性。
2. 代价二,增加出现bug和安全漏洞的可能性。
3. 代价三,随着类发行新的版本,相关的测试负担也增加了。
4. 根据经验,比如Date和BigInteger这样的值类应该实现Serializable,大多数的集合类也应该如此。代表活动实体的类,比如线程池,一般不实现。
5. 为继承而设计的类应该尽可能少地去实现Serializable,用户的接口也是如此。
6. 内部类不应该实现Serializable。
1. 如果没有先认真考虑默认的序列化形式是否合适,则不要贸然接收。
2. 如果一个对象的物理表示法等同于它的逻辑内容,可能就适合于使用默认的序列化形式。
3. 使用transient修饰符,表明这个实例域将从一个类的默认序列化形式中省略掉。
4. 在决定将一个域做成为transient的之前,请一定要确信它的值将是该对象逻辑状态的一部分。
5. 如果在读取整个对象状态的任何其他方法上强制任何同步,则也必须在对象序列化上强制这种同步。
6. 为编写的每个可序列化的类声明一个显式的序列版本UID。
1. 当一个对象被反序列化的时候,对于客户端不应该拥有的对象引用,如果哪个域包含了这样的对象引用,就必须要做保护性拷贝。
1. 如果依赖readResolve进行实例控制,带有对象引用类型的所有实例域则都必须声明为transient的
1. 在一个不能被客户端拓展的类上编写readObject或者writeObject方法的时候。