今天看啥  ›  专栏  ›  minute5

Effective Java理解(一)

minute5  · 掘金  ·  · 2019-08-31 11:46
阅读 14

Effective Java理解(一)

静态工厂方法替换构造函数 - 何时替换

  1. 静态工厂方法含有名字,它能提供更加明确的信息
  2. 当创建对象的代价很大时,需要使用享元模式时
  3. 能返回其返回类型的任何子类型的对象(? extends T),比如java .util. collections
  4. 返回对象的类可以根据输入参数的不同而不同。
  5. 服务提供者框架中编写包含方法的类时,返回的对象的类不需要存在(这句话,单独拿在这儿来说,我是懵逼的),在书中用JDBC来说明了一下,但解释得十分笼统,这里重新释义一下服务提供者框架
    JDBC服务提供者框架关系图.jpg
    1. Class.forName("com.mysql.jdbc.Driver");这样一个语句会实例化一个Driver类(提供服务者实现类),并将这个类的实例注册到DriverManager(服务提供者注册类)。
    2. DriverManager.getConnection("jdbc:mysql://...","...","..."); 这里通过建立连接的URL等信息来获取数据库连接。DriverManager通过传进来的url信息判断出你是要获取那个服务提供者提供的服务。因为1中已经将提供服务者实现类注册到DriverManager了,DriverManager获取到这个服务提供者实现类对象之后,通过调用它的getService(mysql里面是connect方法)方法获取到服务具体实现类对象,返回的却是java.sql.Connection接口对象(因为服务具体实现类实现了Connection接口),这样把服务具体实现类对象隐藏了。提供了很好的扩展性。
    3. 在Java1.6的时候加入了java.util.ServiceLoader,可以通过这个类来实现服务提供者。
静态工厂方法的常用名称:
  1. from —— A 类型转换方法,它接受单个参数并返回此类型的相应实例,例如:Date d = Date.from(instant);
  2. of —— 一个聚合方法,接受多个参数并返回该类型的实例,并把他们合并在一起,例如:Set faceCards = EnumSet.of(JACK, QUEEN, KING);
  3. valueOf —— from 和 to 更为详细的替代 方式,例如:BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  4. instancegetinstance —— 返回一个由其参数 (如果有的话) 描述的实例,但不能说它具有相同的值,例如:StackWalker luke = StackWalker.getInstance(options);
  5. createnewInstance —— 与 instance 或 getInstance 类似,除了该方法保证每个调用返回一个新的实例,例如:Object newArray = Array.newInstance(classObject, arrayLen);
  6. getType —— 与 getInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型,例如:FileStore fs = Files.getFileStore(path);
  7. newType —— 与 newInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型,例如:BufferedReader br = Files.newBufferedReader(path);
  8. type —— getType 和 newType 简洁的替代方式,例如:List litany = Collections.list(legacyLitany);
  • tips: 当构造函数的参数过多使用Builder

依赖注入替换硬连接资源的方式

如果一个类依赖于一个或多个底层资源,这些资源的行为会影响类的行为的时候,不要使用单例或静态的实用类来实现这个类,并且不让类直接创建这些资源。相反,将资源或工厂传递给构造方法(或静态工厂或 builder 模式)。这种称为依赖注入的实践将极大地增强类的灵活性、可重用性和可测试性。

重写equals方法

  1. 自反性: 对于任何非空引用 x,x.equals(x) 必须返回 true。
  2. 对称性: 对于任何非空引用 x 和 y,如果且仅当 y.equals(x) 返回 true 时 x.equals(y) 必须返回 true。
  3. 传递性: 对于任何非空引用 x、y、z,如果 x.equals(y) 返回 true,y.equals(z) 返回 true,则 x.equals(z) 必须返回 true。
  4. 一致性对于任何非空引用 x 和 y,如果在 equals 比较中使用的信息没有修改,则 x.equals(y) 的多次调用必须始终返回 true 或始终返回 false。
  5. 对于任何非空引用 x,x.equals(null) 必须返回 false。
  6. 当重写 equals 方法时,同时也要重写 hashCode 方法。
  7. 不要让 equals 方法试图太聪明。如果只是简单地测试用于相等的属性。
  8. 在 equal 时方法声明中,不要将参数 Object 替换成其他类型。
//正确示范
@Override 
public boolean equals(Object o) {
    if (!(o instanceof MyType))
        return false;
    MyType mt = (MyType) o;
    ...
}
复制代码

实现Comparable接口

  1. 使用Arrays.sort来完成排序
  2. 无论何时实现具有合理排序的值类,都应该让该类实现 Comparable 接口。 比较 compareTo 方法的实现中的字段值时,请避免使用<>运算符。 相反,使用包装类中的静态 compare 方法或 Comparator 接口中的构建方法。
// BROKEN difference-based comparator - violates transitivity!
static Comparator<Object> hashCodeOrder = new Comparator<>() {
    public int compare(Object o1, Object o2) {
        return o1.hashCode() - o2.hashCode();
    }
};
/**
  *不要使用这种技术!它可能会导致整数最大长度溢出和 IEEE 754 浮点运算失真的危险[JLS 15.20.1,15.21.1]。 此外,由此
  *产生的方法不可能比使用上述技术编写的方法快得多。 使用静态 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());
    }
};
&emsp;&emsp;
//或者使用 Comparator 的构建方法:
// Comparator based on Comparator construction method
static Comparator<Object> hashCodeOrder =
        Comparator.comparingInt(o -> o.hashCode());

//java8 比较 正序
someList.sort((Message m1, Message m2) -> m1.getSendDate().compareTo(m2.getSendDate()));
复制代码
参考:
  1. 《effective java》3rd -- Joshua Bloch
  2. JAVA 服务提供者框架介绍



原文地址:访问原文地址
快照地址: 访问文章快照