1. 静态工厂

  • 静态工厂的第 5 个优点是,在编写包含该方法的类时,返回的对象的类不需要存在。他的意思是面向接口编程??就是说我们只需知道接口,具体实现类是否存在没有关系??
  • 只提供静态工厂方法的主要限制是,没有公共或受保护构造方法的类不能被子类化。子类不能够继承父类,想要用父类的方法,只能复合。
public class SubBookOrder {
BookOrder bookOrder = null; public void SubBookOrderTest() {
bookOrder = BookOrder.getTotalPrice("bookName", 10, 23.50);
bookOrder.getTotalPrice();
}
}

2. builder模式

  • JavaBean模式缺陷

    不幸的是,JavaBeans 模式本身有严重的缺陷。由于构造方法在多次调用中被分割,所以在构造过程中 JavaBean

    可能处于不一致的状态。该类没有通过检查构造参数参数的有效性来执行一致性的选项。在不一致的状态下尝试使用对象可能会导致与包含 bug 的代码大相径庭的错误,因此很难调试。一个相关的缺点是,JavaBeans 模式排除了让类不可变的可能性(条目 17),并且需要在程序员的部分增加工作以确保线程安全。

    第一点:使用JavaBean将无法区分哪些是必须哪些是可选。

    第二点:有setter的话,这样类实例之后就能够修改了,不能保证线程安全。

  • 有效性检查。意思是对参数有效性的检查,比如是否为null,是否符合物理常识(比如物体质量不能为负)。

  • Pizza.Builder 是一个带有递归类型参数( recursive type parameter)(条目 30)的泛型类型。 这

    与抽象的 self 方法一起,允许方法链在子类中正常工作,而不需要强制转换。 Java 缺乏自我类型的这种变通解决

    方法被称为模拟自我类型(simulated self-type)的习惯用法。

    Pizzal类
    abstract static class Builder<T extends Builder<T>>
    // Subclasses must override this method to return "this"
    protected abstract T self();
    NyPizza类
    public static class Builder extends Pizza.Builder<Builder>
    @Override protected Builder self() {return this;}
  • 请注意,每个子类 builder 中的 build 方法被声明为返回正确的子类: NyPizza.Builder 的 build 方法返回 NyPizza ,而 Calzone.Builder 中的 build 方法返回 Calzone 。 这种技术,其一个子类的方法被声明为返回在超类中声明的返回类型的子类型,称为协变返回类型(covariant return typing)。 它允许客户端使用这些builder,而不需要强制转换。

    abstract Pizza build();
    
    @Override public NyPizza build() {return new NyPizza(this);}
    
    @Override public Calzone build() {return new Calzone(this);}

3. 单例模式

  1. 通过私有构造方法
  2. 通过静态工厂
  3. 通过枚举类

4. 使用私有构造方法执行非实例化

  • 比如Math或Arrays等类就不需要实例化,他们都是调用静态方法来完成事情。当然由于构造方法私有,该类的子类就不能访问父类构造方法,也就是说该类不能子类化。

5. 依赖注入优于硬连接资源

通过依赖注入的方式,而不是写死的方式,来引入依赖资源,这样会极大 增强类的灵活性,可重用性和可测试性。

6. 避免创建不必要的对象

String s = new String("bikini"); 不好
String s = "bikini"; 好

有限状态机(Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。

还有基本类型和装箱类型,如果使用装箱类型就会创建新对象,所以要我们注意自动装箱,他可能会创建很多不必要的对象。

7. 消除过期的对象引用

当对象在栈中弹出不会被垃圾回收,这是因为栈对这些对象的过期引用。所以需要我们将他们设置成null;

8. 避免使用 Finalizer 和 Cleaner 机制

看不懂,反正不用就对了。。。

9. 使用 try-with-resources 语句替代 try-finally 语句

当必须close的资源时,要使用try-with-resources,这样会更简洁清晰,生成的异常更有用。

10. 重写 equals 方法时遵守通用约定

重写equals方法是有些约定,要满足自反性,一致性,对称性,传递性,非空性,IDE和AutoValue 框架提供了自动生成,这些都遵守以下:

  1. 使用 == 运算符检查参数是否为该对象的引用。如果是,返回 true。这只是一种性能优化,但是如果这种比较可

    能很昂贵的话,那就值得去做。
  2. 使用 instanceof 运算符来检查参数是否具有正确的类型。 如果不是,则返回 false。 通常,正确的类型是

    equals 方法所在的那个类。 有时候,改类实现了一些接口。 如果类实现了一个接口,该接口可以改进 equals 约

    定以允许实现接口的类进行比较,那么使用接口。 集合接口(如 Set,List,Map 和 Map.Entry)具有此特性。
  3. 参数转换为正确的类型。因为转换操作在 instanceof 中已经处理过,所以它肯定会成功。
  4. 对于类中的每个“重要”的属性,请检查该参数属性是否与该对象对应的属性相匹配。如果所有这些测试成功,

    返回 true,否则返回 false。如果步骤 2 中的类型是一个接口,那么必须通过接口方法访问参数的属性;如果类型

    是类,则可以直接访问属性,这取决于属性的访问权限

11. 当覆盖 equals 时,始终覆盖 hashCode

当进行equals比较时,先比较对象的hashCode,然后再去比较对象的每个属性是否相等。如果不重写hashCode,那么即使是相等的对象,最终返回结果也可能是false。

12. toString

toSting当然也可以自动生成。如果对生成的字符串没有格式要求,那么自动生成的是好的。但是如果对于生成的字符串有格式要求,比如phonenumber,这时用自动生成就不太好了。

//这就是有格式要求的toString方法
@Override
public String toString() {
return String.format("%03d-%03d-%04d",areaCode, prefix, lineNum);
}

13. 谨慎地重写 clone 方法

通常,复制功能最好由构造方法或工厂提供。 这个规则的一个明显的例外是数组,它最好用 clone 方法复制。

// Copy constructor
public Yum(Yum yum) { ... }; // Copy factory
public static Yum newInstance(Yum yum) { ... };

14. 考虑实现 Comparable 接口

//使用静态 compare 方法:
// Comparator based on static compare method
static Comparator<Object> hashCodeOrder = new Comparator<>() {
public int compare(Object o1, Object o2) {
return Integer.compare(o1.hashCode(), o2.hashCode());
}
};
//或者使用 Comparator 的构建方法:
// Comparator based on Comparator construction method
static Comparator<Object> hashCodeOrder =
Comparator.comparingInt(o -> o.hashCode());

15. 使类和成员的可访问性最小化

显而易见这是为了封装解耦,JDK使用了模块级别,但是普通程序员还是不要使用模块来控制访问。在公共类中的公共静态final除了作为常量以外,不应该有公共属性。确保 public static final 属性引用的对象是不可变的(如果是可变的,那么客户端就能对其访问并修改,造成安全漏洞)。

如果你想用这个数组:

public static final Thing[] VALUES = { ... };

但是又害怕客户端对其进行修改,可以进行如下操作:

  1. 你可以使公共数组私有并添加一个公共的不可变列表:

    private static final Thing[] PRIVATE_VALUES = { ... };
    public static final List<Thing> VALUES =
    Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
  2. 或者,可以将数组设置为 private,并添加一个返回私有数组拷贝的公共方法:

    private static final Thing[] PRIVATE_VALUES = { ... };
    public static final Thing[] values() {
    return PRIVATE_VALUES.clone();
    }

16. 在公共类中使用访问方法而不是公共属性

  • 当然,对于公共类来说,坚持面向对象是正确的:由于这些类的数据属性可以直接被访问,因此这些类不提供封装的好处(条目 15)。 如果不更改 API,则无法更改其表示形式,无法强制执行不变量,并且在访问属性时无法执行辅助操作。

    如果直接访问共有属性而不是方法,到时候我们想更改一些业务逻辑就没法了。

17. 最小化可变性

如果你创建一个类,最好是不可变类,除非你有性能上的要求,需要有可变伙伴类。比如String和StringBuilder。类中属性最好是final,但有时为了性能在一个不可变类中也可能有公共可变属性。

18. 组合优于继承

看不懂。

50. 必要时进行防御性拷贝

  • 即使编写的代码是没有set方法的,但是由于所依赖的类是可变的,而导致所编写的类也是可变的。比如Date是一个可变类。

    public final class Period {
    private final Date start;
    private final Date end;
    /**
    * @param start the beginning of the period
    * @param end the end of the period; must not precede start
    * @throws IllegalArgumentException if start is after end
    * @throws NullPointerException if start or end is null
    */
    public Period(Date start, Date end) {
    if (start.compareTo(end) > 0)
    throw new IllegalArgumentException(
    start + " after " + end);
    this.start = start;
    this.end = end;
    }
    public Date start() {
    return start;
    }
    public Date end() {
    return end;
    }
    ... // Remainder omitted
    }

    虽然此类没有set,但是由于Date类可变(Date类有set方法),导致该类也是可变的。

Effective Java 笔记的更多相关文章

  1. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  2. Effective java笔记(二),所有对象的通用方法

    Object类的所有非final方法(equals.hashCode.toString.clone.finalize)都要遵守通用约定(general contract),否则其它依赖于这些约定的类( ...

  3. effective java笔记之单例模式与序列化

    单例模式:"一个类有且仅有一个实例,并且自行实例化向整个系统提供." 单例模式实现方式有多种,例如懒汉模式(等用到时候再实例化),饿汉模式(类加载时就实例化)等,这里用饿汉模式方法 ...

  4. effective java笔记之java服务提供者框架

    博主是一名苦逼的大四实习生,现在java从业人员越来越多,面对的竞争越来越大,还没走出校园,就TM可能面临失业,而且对那些增删改查的业务毫无兴趣,于是决定提升自己,在实习期间的时间还是很充裕的,期间自 ...

  5. Effective java笔记(一),创建与销毁对象

    1.考虑用静态工厂方法代替构造器 类的一个实例,通常使用类的公有的构造方法获取.也可以为类提供一个公有的静态工厂方法(不是设计模式中的工厂模式)来返回类的一个实例.例如: //将boolean类型转换 ...

  6. Effective java笔记(四),泛型

    泛型为集合提供了编译时类型检查. 23.不要在代码中使用原生态类型 声明中具有一个或多个类型参数的类或接口统称为泛型.List<E>是一个参数化类,表示元素类型为E的列表.为了提供兼容性, ...

  7. Effective java笔记(九),并发

    66.同步访问共享的可变数据 JVM对不大于32位的基本类型的操作都是原子操作,所以读取一个非long或double类型的变量,可以保证返回的值是某个线程保存在该变量中的,但它并不能保证一个线程写入的 ...

  8. Effective java笔记(八),异常

    57.只针对异常的情况才使用异常 try { int i = 0; while(true) range[i++].climb(); }catch(ArrayIndexOutOfBoundsExcept ...

  9. Effective java笔记(七),通用程序设计

    45.将局部变量的作用域最小化 将局部变量的作用域最小化,可以增强代码的可读性和可维护性,并降低出错的可能性. Java允许在任何可以出现语句的地方声明变量(C语言中局部变量要在代码块开头声明),要使 ...

  10. Effective java笔记(六),方法

    38.检查参数的有效性 绝大多数方法和构造器对于传递给它们的参数值都会有限制.如,对象引用不能为null,数组索引有范围限制等.应该在文档中指明所有这些限制,并在方法的开头处检查参数,以强制施加这些限 ...

随机推荐

  1. deepin-terminal改造之路

    目录 1. 背景介绍 2. 下载源码 3. 依赖检查及安装 4. 改造之路 4.1 终端透明度快捷键 4.1.1 设置面板增加选项内容 4.1.2 添加配置解析内容 4.1.3 功能实现 4.1.4 ...

  2. 在Arch上使用Fcitx5

    目录 卸载Fcitx4 安装Fcitx5 配置 修改环境变量 系统登陆后默认启动Fcitx5输入法 配置主题 最终使用效果 参考文档 我是一个Arch+KDE的用户,所以下面的方法可能不适合所有的Li ...

  3. tibco EMS 8.2.0安装

    安装环境 序号 项目 值 1 OS版本 Red Hat Enterprise Linux Server release 7.1 (Maipo) 2 内核版本 3.10.0-229.el7.x86_64 ...

  4. Codeforces 784B Santa Claus and Keyboard Check

    题面: 传送门 B. Santa Claus and Keyboard Check Input file: standard input Output file: standard output Time ...

  5. python plt画图横纵坐标0点重合

    # -*- coding: utf-8 -*- import numpy as np import matplotlib.mlab as mlab import matplotlib.pyplot a ...

  6. 使用shell脚本替换Hadoop配置文件的值

    因为懒汉式的实现是线程安全的,所以会降低整个访问速度,而且每次访问都要判断一次.有没有更好的方式实现呢?可以使用"双重检查枷锁"的方式来实现. 所谓"双重检查加锁&quo ...

  7. 使用jhipster 加速java web开发

    jhipster,中文释义: Java 热爱者! JHipster is a development platform to quickly generate, develop, & depl ...

  8. 制作API离线chm帮助文件教程

    当我们开发好一个通信库的时候,我们希望给这个通信库配备一个帮助文档,最好的方式,就是有一个离线的chm版本的API文档,这样别人在使用的时候,就可以清楚看到命名空间.类的结构,同时也能看到每个方法和属 ...

  9. Bonuses on a Line Gym - 102569B

    题目链接:https://vjudge.net/problem/Gym-102569B 题意:数轴上有N个点,从0出发最多走t步问最多经过几个点. 思路:分开存负数点和整数点,然后枚举每个端点,某个点 ...

  10. SynchronousQueue核心源码分析

    一.SynchronousQueue的介绍 SynchronousQueue是一个不存储元素的阻塞队列.每一个put操作必须等待一个take操作,否则不能继续添加元素.SynchronousQueue ...